我可以使用相同的子字符串作为不同捕获的一部分吗?

时间:2016-03-07 19:08:40

标签: c# regex

我想创建一个允许我将CamelCase转换为Title Case的函数。对于正则表达式来说,这似乎是一项很好的任务,但如果您有更好的解决方案,我不会致力于使用正则表达式。

这是我的第一次尝试在大多数情况下有效,但我会在几行中遇到一些问题:

private static Regex camelSplitRegex = new Regex(@"(\S)([A-Z])");
private static String camelReplacement = "$1 $2";

public String SplitCamel(String text){
    return camelSplitRegex.Replace(text, camelReplacement);
}

正则表达式模式查找非空白字符(第一次捕获),后跟大写字母(第二次捕获)。在函数中,Regex.Replace用于在第一次和第二次捕获之间插入空格。

这适用于许多例子:

  • SplitCamel("privateField")返回"private Field"
  • SplitCamel("PublicMethod")返回"Public Method"
  • SplitCamel(" LeadingSpace")根据需要返回" Leading Space",而不在“领导”之前插入额外的空格。

我遇到的问题是处理多个连续的大写字母时。

  • SplitCamel("NASA")返回“N AS A”而不是“N A S A”
  • SplitCamel("C3PO")返回“C3 PO”而非“C3 P O”
  • SplitCamel("CAPS LOCK FEVER")返回“C AP S L OC K F EV E R”而非“C A P S L O C K F E V E R”

在这些情况下,我认为问题是每个大写字母只会被捕获为\S[A-Z],但在一场比赛中不能\S[A-Z]在下一场比赛中。

我的主要问题是,“.NET正则表达式引擎是否有某种方式支持在连续匹配时使用相同的子字符串作为不同的捕获?”其次,是否有更好的方法来分裂骆驼案?

3 个答案:

答案 0 :(得分:4)

private static Regex camelSplitRegex = new Regex(@"(?<=\w)(?=[A-Z])");
private static String camelReplacement = " ";

完成这项工作。

你的模式的问题是当你有字符串“ABCD”时,\S匹配A而([A-Z])匹配B而你获得“A BCD”,但是对于下一个替换B已经是由模式消耗,不能再使用了。

方法是使用不消耗字符的外观(一个lookbehind (?<=...)和一个前瞻(?=...),它们只是测试当前位置string,这就是你在替换字符串中不需要任何引用的原因,你只需要在当前位置放置一个空格。

\w字符类包含unicode字母,unicode数字和下划线。如果要将搜索限制为ASCII数字和字母,请改用[0-9a-zA-Z]

更确切地说:

  • 对于unicode,请使用与重音字母和其他字母和数字一起使用的(?<=[\p{L}\p{N}])(?=\p{Lu})
  • for ASCII use (?<=[a-zA-Z0-9])(?=[A-Z])

答案 1 :(得分:2)

这是一种非正则的表达方式。

public static string SplitCamel(this string stuff)
{
    var builder = new StringBuilder();
    char? prev = null;
    foreach (char c in stuff)
    {
        if (prev.HasValue && !char.IsWhiteSpace(prev.Value) && 'A' <= c && c <= 'Z') 
            builder.Append(' ');
        builder.Append(c);
        prev = c;
    }

    return builder.ToString();
}

以下

Console.WriteLine("'{0}'", "privateField".SplitCamel());
Console.WriteLine("'{0}'", "PublicMethod".SplitCamel());
Console.WriteLine("'{0}'", " LeadingSpace".SplitCamel());
Console.WriteLine("'{0}'", "NASA".SplitCamel());
Console.WriteLine("'{0}'", "C3PO".SplitCamel());
Console.WriteLine("'{0}'", "CAPS LOCK FEVER".SplitCamel());

打印

  

'private Field'

     

'公共方法'

     

'领先空间'

     

'N A S A'

     

'C3 P O'

     

'C A P S L O C K F E V E R'

答案 2 :(得分:0)

请考虑切换到值类型字符串而不是字符串类。更新到此。

 private static Regex camelSplitRegex = new Regex(@"(^\S)?([A-Z])");