25

For example:

thisIsMySample 

should be:

this_Is_My_Sample

My code:

System.Text.RegularExpressions.Regex.Replace(input, "([A-Z])", "_$0", System.Text.RegularExpressions.RegexOptions.Compiled);

It works fine, but if the input is changed to:

ThisIsMySample

the output will be:

_This_Is_My_Sample

How can first occurrence be ignored?

4

7 回答 7

44

非正则表达式解决方案

string result = string.Concat(input.Select((x,i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())); 

似乎也很快:Regex:2569ms,C#:1489ms

Stopwatch stp = new Stopwatch();
stp.Start();
for (int i = 0; i < 1000000; i++)
{
    string input = "ThisIsMySample";
    string result = System.Text.RegularExpressions.Regex.Replace(input, "(?<=.)([A-Z])", "_$0",
            System.Text.RegularExpressions.RegexOptions.Compiled);
}
stp.Stop();
MessageBox.Show(stp.ElapsedMilliseconds.ToString());
// Result 2569ms

Stopwatch stp2 = new Stopwatch();
stp2.Start();
for (int i = 0; i < 1000000; i++)
{
    string input = "ThisIsMySample";
    string result = string.Concat(input.Select((x, j) => j > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString()));
}
stp2.Stop();
MessageBox.Show(stp2.ElapsedMilliseconds.ToString());
// Result: 1489ms
于 2013-09-13T08:19:33.890 回答
15

您可以使用lookbehind来确保每个匹配项前面至少有一个字符:

System.Text.RegularExpressions.Regex.Replace(input, "(?<=.)([A-Z])", "_$0",
                      System.Text.RegularExpressions.RegexOptions.Compiled);

lookaheads 和lookbehinds 允许您对匹配周围的文本进行断言,而不包括匹配中的文本。

于 2013-09-13T07:57:58.627 回答
4

也许喜欢;

var str = Regex.Replace(input, "([A-Z])", "_$0", RegexOptions.Compiled);
if(str.StartsWith("_"))
   str = str.SubString(1);
于 2013-09-13T07:56:16.033 回答
3
// (Preceded by a lowercase character or digit) (a capital) => The character prefixed with an underscore
var result = Regex.Replace(input, "(?<=[a-z0-9])[A-Z]", m => "_" + m.Value);
result = result.ToLowerInvariant();
  • 这适用于PascalCasecamelCase
  • 它不创建前导或尾随下划线。
  • 它在字符串中保留任何非单词字符和下划线序列,因为它们看起来是故意的,例如__HiThere_Guys变得__hi_there_guys
  • 数字后缀(故意)被认为是单词的一部分,例如NewVersion3become new_version3
  • 数字前缀遵循原始大小写,例如3VersionsHere变为3_versions_here,但3rdVersion变为3rd_version
  • 不幸的是,不支持大写的两个字母的首字母缩写词(例如 in IDNumber,其中ID将被视为一个单独的词),如Microsoft 的大写约定中所建议的那样,因为它们与其他情况相冲突。总的来说,我建议抵制这一准则,因为它似乎是对大写首字母缩略词惯例的任意例外。坚持IdNumber
于 2016-04-11T12:14:00.563 回答
2

详细阐述 sa_ddam213 的解决方案,我的扩展了这个:

public static string GetConstStyleName(this string value)
        {
            return string.Concat(value.Select((x, i) =>
            {
                //want to avoid putting underscores between pairs of upper-cases or pairs of numbers, or adding redundant underscores if they already exist.
                bool isPrevCharLower = (i == 0) ? false : char.IsLower(value[i - 1]);
                bool isPrevCharNumber = (i == 0) ? false : char.IsNumber(value[i - 1]);
                return (isPrevCharLower && (char.IsUpper(x) || char.IsNumber(x))) //lower-case followed by upper-case or number needs underscore
                    || (isPrevCharNumber && (char.IsUpper(x))) //number followed by upper-case needs underscore
                    ? "_" + x.ToString() : x.ToString();
            })).ToUpperInvariant();
        }
于 2014-10-03T16:59:09.320 回答
1

用于".([A-Z])"您的正则表达式,然后"_$1"用于替换。因此,您使用捕获的字符串进行替换,并且使用前导.确定您没有捕获字符串的第一个字符。

于 2013-09-13T07:57:29.323 回答
1

您需要通过定义要完全忽略第一个字符来修改您的正则表达式以不匹配第一个字符

.([A-Z])

上面的正则表达式只是排除了第一个出现的每个字符,因为它不在大括号中,所以它会在匹配组中。

现在您需要像 Bibhu 指出的那样匹配第二组:

System.Text.RegularExpressions.Regex.Replace(s, "(.)([A-Z])", "$1_$2", System.Text.RegularExpressions.RegexOptions.Compiled);
于 2013-09-13T07:56:15.683 回答