将PascalCase字符串拆分为单独的单词

时间:2010-07-09 19:53:39

标签: .net regex

我正在寻找一种分割PascalCase字符串的方法,例如“MyString”,分成单词 - “我的”,“字符串”。另一个用户posed the question for bash,但我想知道如何使用常规正则表达式或至少在.NET中。

如果你能找到一种方法来分割(并可选择地大写)camelCase字符串: “myString”变为“my”和“String”,可以选择大写/小写字符串中的一个或两个。

10 个答案:

答案 0 :(得分:13)

请参阅此问题:Is there a elegant way to parse a word and add spaces before capital letters?其接受的答案涵盖了您想要的内容,包括数字和连续的几个大写字母。虽然此示例的单词以大写字母开头,但当第一个单词为小写时,它同样有效。

string[] tests = {
   "AutomaticTrackingSystem",
   "XMLEditor",
   "AnXMLAndXSLT2.0Tool",
};


Regex r = new Regex(
    @"(?<=[A-Z])(?=[A-Z][a-z])|(?<=[^A-Z])(?=[A-Z])|(?<=[A-Za-z])(?=[^A-Za-z])"
  );

foreach (string s in tests)
  r.Replace(s, " ");

以上将输出:

[Automatic][Tracking][System]
[XML][Editor]
[An][XML][And][XSLT][2.0][Tool]

答案 1 :(得分:9)

为了提供RegEx和循环解决方案的替代方案,这里提供的所有内容都是使用LINQ的答案,LINQ也处理驼峰案例和首字母缩略词:

    string[] testCollection = new string[] { "AutomaticTrackingSystem", "XSLT", "aCamelCaseWord" };
    foreach (string test in testCollection)
    {
        // if it is not the first character and it is uppercase
        //  and the previous character is not uppercase then insert a space
        var result = test.SelectMany((c, i) => i != 0 && char.IsUpper(c) && !char.IsUpper(test[i - 1]) ? new char[] { ' ', c } : new char[] { c });
        Console.WriteLine(new String(result.ToArray()));
    }

这个输出是:

Automatic Tracking System  
XSLT  
a Camel Case Word 

答案 2 :(得分:5)

Answered in a different question

void Main()
{
    "aCamelCaseWord".ToFriendlyCase().Dump();
}

public static class Extensions
{
    public static string ToFriendlyCase(this string PascalString)
    {
        return Regex.Replace(PascalString, "(?!^)([A-Z])", " $1");
    }
}

输出a Camel Case Word.Dump()只打印到控制台)。

答案 3 :(得分:4)

怎么样:

static IEnumerable<string> SplitPascalCase(this string text)
{
    var sb = new StringBuilder();
    using (var reader = new StringReader(text))
    {
        while (reader.Peek() != -1)
        {
            char c = (char)reader.Read();
            if (char.IsUpper(c) && sb.Length > 0)
            {
                yield return sb.ToString();
                sb.Length = 0;
            }

            sb.Append(c);
        }
    }

    if (sb.Length > 0)
        yield return sb.ToString();
}

答案 4 :(得分:2)

为目标
  • a)创建优化性能的功能
  • b)对CamelCase有自己的看法,其中大写的首字母缩略词没有被分开(我完全接受这不是骆驼或pascal案例的标准定义,但这不是一种罕见的用法):“TestTLAContainingCamelCase”变为“Test TLA”包含骆驼案“(TLA =三字母缩写词)

因此我创建了以下(非正则表达式,详细,但面向性能)函数

public static string ToSeparateWords(this string value)
{
    if (value==null){return null;}
    if(value.Length <=1){return value;}
    char[] inChars = value.ToCharArray();
    List<int> uCWithAnyLC = new List<int>();
    int i = 0;
    while (i < inChars.Length && char.IsUpper(inChars[i])) { ++i; }
    for (; i < inChars.Length; i++)
    {
        if (char.IsUpper(inChars[i]))
        {
            uCWithAnyLC.Add(i);
            if (++i < inChars.Length && char.IsUpper(inChars[i]))
            {
                while (++i < inChars.Length) 
                {
                    if (!char.IsUpper(inChars[i]))
                    {
                        uCWithAnyLC.Add(i - 1);
                        break;
                    }
                }
            }
        }
    }
    char[] outChars = new char[inChars.Length + uCWithAnyLC.Count];
    int lastIndex = 0;
    for (i=0;i<uCWithAnyLC.Count;i++)
    {
        int currentIndex = uCWithAnyLC[i];
        Array.Copy(inChars, lastIndex, outChars, lastIndex + i, currentIndex - lastIndex);
        outChars[currentIndex + i] = ' ';
        lastIndex = currentIndex;
    }
    int lastPos = lastIndex + uCWithAnyLC.Count;
    Array.Copy(inChars, lastIndex, outChars, lastPos, outChars.Length - lastPos);
    return new string(outChars);
}

最令人惊讶的是性能测试。每个函数使用1 000 000次迭代

regex pattern used = "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))"
test string = "TestTLAContainingCamelCase":
static regex:      13 302ms
Regex instance:    12 398ms
compiled regex:    12 663ms
brent(above):         345ms
AndyRose:           1 764ms
DanTao:               995ms

Regex实例方法只比静态方法略快,甚至超过一百万次迭代(我看不到使用RegexOptions.Compiled标志的好处),而Dan Tao的非常简洁的代码几乎和我不太清楚的代码!

答案 5 :(得分:1)

var regex = new Regex("([A-Z]+[^A-Z]+)");
var matches = regex.Matches("aCamelCaseWord")
    .Cast<Match>()
    .Select(match => match.Value);
foreach (var element in matches)
{
    Console.WriteLine(element);
}

打印

Camel
Case
Word

(正如你所看到的,它没有处理camelCase - 它放弃了领先的“a”。)

答案 6 :(得分:0)

使用\W检查正则表达式的开头是否出现非单词字符并将各个字符串保持在一起,然后拆分单词。

类似于:\W([A-Z][A-Za-z]+)+

For:sdcsds sd aCamelCaseWord as dasd as aSscdcacdcdc PascelCase DfsadSsdd sd 输出:

48: PascelCase
59: DfsadSsdd

答案 7 :(得分:0)

在Ruby中:

"aCamelCaseWord".split /(?=[[:upper:]])/
=> ["a", "Camel", "Case", "Word"]

我在这里使用正面预测,以便我可以在每个大写字母前分割字符串。这样我就可以保存任何初始的小写部分。

答案 8 :(得分:0)

    public static string PascalCaseToSentence(string input)
    {
        if (input == null) return "";

        string output = Regex.Replace(input, @"(?<=[A-Z])(?=[A-Z][a-z])|(?<=[^A-Z])(?=[A-Z])|(?<=[A-Za-z])(?=[^A-Za-z])", m => " " + m.Value);
        return output;
    }

基于Shimmy的回答。

答案 9 :(得分:0)

string.Concat(str.Select(x => Char.IsUpper(x) ? " " + x : x.ToString())).TrimStart(' ').Dump();

与使用Regex相比,这是一种更好的方法,转储仅用于打印到控制台