正则表达式:将驼峰案例转换为带下划线的所有大写字母

时间:2010-12-22 16:08:01

标签: c# regex

可以使用哪个正则表达式进行以下转换?

City -> CITY
FirstName -> FIRST_NAME
DOB -> DOB
PATId -> PAT_ID
RoomNO -> ROOM_NO

以下几乎可行 - 它只是在单词的开头添加了一个额外的下划线:

var rgx = @"(?x)( [A-Z][a-z,0-9]+ | [A-Z]+(?![a-z]) )";

var tests = new string[] { "City",
                           "FirstName",
                           "DOB",
                           "PATId",
                           "RoomNO"};

foreach (var test in tests)
    Console.WriteLine("{0} -> {1}", test, 
                       Regex.Replace(test, rgx, "_$0").ToUpper());


// output:
// City -> _CITY
// FirstName -> _FIRST_NAME
// DOB -> _DOB
// PATId -> _PAT_ID
// RoomNO -> _ROOM_NO

6 个答案:

答案 0 :(得分:16)

从John M Gant的想法中加入下划线然后大写,我认为这个正则表达式应该有效:

([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])

替换为:

$1$3_$2$4

您可以重命名捕获区域,以使替换字符串更好一些。只有$ 1或$ 3应该有一个值,相同的是2美元和4美元。一般的想法是在以下情况下添加下划线:

  • 有两个大写字母后跟一个小写字母,将下划线放在两个大写字母之间。 (PATId - > PAT_Id)
  • 有一个小写字母后跟一个大写字母,将下划线放在两个中间。 (RoomNO - > Room_NO和FirstName - > First_Name)

希望这有帮助。

答案 1 :(得分:11)

我建议使用简单的Regex插入下划线,然后string.ToUpper()转换为大写。

Regex.Replace(test, @"(\p{Ll})(\p{Lu})", "$1_$2").ToUpper()

这是两个操作而不是一个,但对我而言,它比一个复杂的正则表达式替换更容易阅读。

答案 2 :(得分:2)

我可能想出一个可以做到这一点的正则表达式...但我相信变革性的正则表达式可能不是正确的答案。我建议你拿走你已经拥有的东西,然后将第一个字符(前导下划线)从输出中删除。 CPU时间可能与此相同或更少,并且您的编码时间无关紧要。

尝试:(?x)(.)( [A-Z][a-z,0-9]+ | [A-Z]+(?![a-z]) )并将代码更改为输出$ 0_ $ 1而不是_ $ 0 &lt; - 误导和失败尝试梦想我说的是一个愚蠢的想法。< / p>

答案 3 :(得分:1)

看起来像Rails does it使用多个正则表达式。

var rgx = @"([A-Z]+)([A-Z][a-z])";
var rgx2 = @"([a-z\d])([A-Z])";

foreach (var test in tests)
{
    var result = Regex.Replace(test, rgx, "$1_$2");
    result = Regex.Replace(result, rgx2, "$1_$2");
    result = result.ToUpper();
    Console.WriteLine("{0} -> {1}", test, result);
}

答案 4 :(得分:1)

我意识到这是一个老问题,但它仍然经常出现,所以我决定分享我自己的方法。

不是试图用替换来做,而是想找到字符串中的所有“单词”,然后将它们转换为大写并加入:

var tests = new string[] { "City",
                "FirstName",
                "DOB",
                "PATId",
                "RoomNO"};
foreach (var test in tests)
    Console.WriteLine("{0} -> {1}", test,
                        String.Join("_", new Regex(@"^(\p{Lu}(?:\p{Lu}*|[\p{Ll}\d]*))*$")
                            .Match(test)
                            .Groups[1]
                            .Captures
                            .Cast<Capture>()
                            .Select(c => c.Value.ToUpper())));

不是非常简洁,但允许你专注于定义“单词”是什么,而不是与锚点,分隔符等等进行斗争。在这种情况下,我将一个单词定义为以大写字母开头,后跟一系列大写字母或混合使用小写和大写字母的单词。我本可以想要分开数字序列。 "^(\p{Lu}(?:\p{Lu}*|\p{Ll}*)|\d+)*$"可以解决问题。或许我想将数字作为前一个大写单词的一部分,然后我做"^(\p{Lu}(?:[\p{Lu}\d]*|[\p{Ll}\d]*))*$"

答案 5 :(得分:0)

这里没有javascript答案,所以也可以添加它。

(这是使用@John McDonald的正则表达式)

var text = "fooBar barFoo";
var newText = text.replace(/([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])/g, "$1$3_$2$4");
newText.toLowerCase()