Разделить строку PascalCase на отдельные слова - PullRequest
7 голосов
/ 09 июля 2010

Я ищу способ разделения строк PascalCase, например «MyString», на отдельные слова - «My», «String». Другой пользователь задал вопрос для bash, но я хочу знать, как это сделать с общими регулярными выражениями или хотя бы в .NET.

Бонус, если вы можете найти способ также разделить (и при желании использовать заглавные буквы) строки camelCase: например, «myString» становится «my» и «String» с возможностью ввода заглавных / строчных букв одной или обеих строк.

Ответы [ 9 ]

13 голосов
/ 10 июля 2010

См. Этот вопрос: Существует ли элегантный способ синтаксического анализа слова и добавления пробелов перед заглавными буквами? Принятый ответ охватывает то, что вы хотите, включая цифры и несколько заглавных букв в строке. Хотя в этом примере слова начинаются с заглавной буквы, оно одинаково верно, если первое слово написано строчными буквами.

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]
9 голосов
/ 02 ноября 2010

Просто для того, чтобы предоставить альтернативу для RegEx и циклических решений, все готово, представленные здесь, ответ с использованием 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 
5 голосов
/ 10 июля 2010

Ответили на другой вопрос :

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() просто печатает на консоль).

4 голосов
/ 10 июля 2010

Как насчет:

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();
}
2 голосов
/ 04 августа 2014

с целями

  • а) Создание функции, оптимизирующей производительность
  • б) Мой собственный взгляд на CamelCase, в котором прописные аббревиатуры не были разделены (я полностью согласен, что это не стандартное определение случая верблюда или паскаля, но это не редкое использование): "TestTLAContainedCamelCase" становится "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), а очень лаконичный код Дэна Тао был почти таким же быстрым, как мой гораздо менее понятный код!

1 голос
/ 09 июля 2010
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".)

0 голосов
/ 23 февраля 2016
    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;
    }

На основании ответа Шимми.

0 голосов
/ 10 июля 2010

в рубине:

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

Я использую положительный прогноз, чтобы разделить строку прямо перед каждой заглавной буквой. Это позволяет мне сохранить любую начальную строчную часть.

0 голосов
/ 10 июля 2010

Убедитесь, что в начале вашего регулярного выражения присутствует не состоящий из символов символ с \W и соберите отдельные строки вместе, затем разбейте слова.* Для: sdcsds sd aCamelCaseWord as dasd as aSscdcacdcdc PascelCase DfsadSsdd sd Выходы:

48: PascelCase
59: DfsadSsdd
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...