есть ли элегантный способ разобрать слово и добавить пробелы перед заглавными буквами - PullRequest
19 голосов
/ 23 июня 2010

Мне нужно проанализировать некоторые данные, и я хочу преобразовать

AutomaticTrackingSystem

в

Automatic Tracking System

, по существу ставя пробел перед любой заглавной буквой (кроме первой, конечно)

Ответы [ 7 ]

26 голосов
/ 23 июня 2010

Вы можете использовать обходные пути, например:

string[] tests = {
   "AutomaticTrackingSystem",
   "XMLEditor",
};

Regex r = new Regex(@"(?!^)(?=[A-Z])");
foreach (string test in tests) {
   Console.WriteLine(r.Replace(test, " "));
}

Это печатает ( как видно на ideone.com ):

Automatic Tracking System
X M L Editor

Регулярное выражение (?!^)(?=[A-Z])состоит из двух утверждений:

  • (?!^) - т.е. мы не находимся в начале строки
  • (?=[A-Z]) - т.е. мы находимся непосредственно перед заглавной буквой

Смежные вопросы

Ссылки


Разделение разницы

Здесь использование утверждений действительно имеет значение, когда у вас есть несколько различных правил, и / или вы хотите Split вместо Replace.Этот пример сочетает в себе оба:

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

Regex r = new Regex(
   @"  (?<=[A-Z])(?=[A-Z][a-z])    # UC before me, UC lc after me
    |  (?<=[^A-Z])(?=[A-Z])        # Not UC before me, UC after me
    |  (?<=[A-Za-z])(?=[^A-Za-z])  # Letter before me, non letter after me
    ",
   RegexOptions.IgnorePatternWhitespace
);
foreach (string test in tests) {
   foreach (string part in r.Split(test)) {
      Console.Write("[" + part + "]");
   }
   Console.WriteLine();
}

Это печатает ( как видно на ideone.com ):

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

Похожие вопросы

19 голосов
/ 23 июня 2010

Без регулярных выражений вы можете сделать что-то вроде (или, возможно, что-то более краткое, используя LINQ):

(Примечание: нет проверки ошибок, вы должны добавить ее)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SO
{
    class Program
    {
        static void Main(string[] args)
        {
            String test = "AStringInCamelCase";
            StringBuilder sb = new StringBuilder();

            foreach (char c in test)
            {
                if (Char.IsUpper(c))
                {
                    sb.Append(" ");
                }
                sb.Append(c);
            }

            if (test != null && test.Length > 0 && Char.IsUpper(test[0]))
            {
                sb.Remove(0, 1);
            }

            String result = sb.ToString();
            Console.WriteLine(result);
        }
    }
}

это дает вывод

A String In Camel Case
4 голосов
/ 23 июня 2010

Я только что написал функцию, чтобы сделать именно это. :)

Заменить ([a-z])([A-Z]) на $1 $2 (или \1 \2 на других языках).

У меня также есть замена для ([A-Z]+)([A-Z][a-z]) - это преобразует такие вещи, как "NumberOfABCDThings" в "Number of ABCD Things"

Так что в C # это будет выглядеть примерно так:

Regex r1 = new Regex(@"([a-z])([A-Z])");
Regex r2 = new Regex(@"([A-Z]+)([A-Z][a-z])");

NewString = r1.Replace( InputString , "$1 $2");
NewString = r2.Replace( NewString , "$1 $2");

(хотя, возможно, есть более хитрый способ написать это)

Если у вас могут быть знаки препинания или цифры, я думаю, вы могли бы попробовать ([^A-Z])([A-Z]) для первого совпадения.

Хммм, еще один способ написания этих регулярных выражений с использованием lookbehind и lookahead, это просто сопоставить позицию и вставить пробел - то есть (?<=[a-z])(?=[A-Z]) и (?<=[A-Z]+)(?=[A-Z][a-z]) и в обоих случаях заменить просто "" - не уверен Может быть преимущества этого метода, но это интересный способ. :)

3 голосов
/ 23 июня 2010

Очевидно, есть опция для обратного регулярного выражения :-) Теперь мы можем исключить обращение строк, вот еще один способ сделать это:

using System;
using System.Linq;
using System.Text.RegularExpressions;

class MainClass
{
    public static void Main (string[] args)
    {
        Regex ry = new Regex
              (@"([A-Z][a-z]+|[A-Z]+[A-Z]|[A-Z]|[^A-Za-z]+[^A-Za-z])", 
              RegexOptions.RightToLeft);


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


        foreach(string t in tests)
        {
            Console.WriteLine("\n\n{0} -- {1}", t, ry.Replace(t, " $1"));   
        }

    }


}

Выход:

AutomaticTrackingSystem --  Automatic Tracking System


XMLEditor --  XML Editor


AnXMLAndXSLT2.0Tool --  An XML And XSLT 2.0 Tool


NumberOfABCDThings --  Number Of ABCD Things


AGoodMan --  A Good Man


CodeOfAGoodMan --  Code Of A Good Man
0 голосов
/ 29 августа 2016

Просто используйте этот linq one-liner: (у меня отлично работает)

public static string SpaceCamelCase(string input)
{
    return input.Aggregate(string.Empty, (old, x) => $"{old}{(char.IsUpper(x) ? " " : "")}{x}").TrimStart(' ');
}
0 голосов
/ 23 июня 2010

Попробуйте это:

using System;
using System.Linq;
using System.Text.RegularExpressions;

class MainClass
{
    public static void Main (string[] args)
    {
        var rx = new Regex
                (@"([a-z]+[A-Z]|[A-Z][A-Z]+|[A-Z]|[^A-Za-z][^A-Za-z]+)");

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

        foreach(string t in tests)
        {
            string y = Reverse(t);
            string x = Reverse( rx.Replace(y, @" $1") );
            Console.WriteLine("\n\n{0} -- {1}",y,x);    
        }

    }

    static string Reverse(string s)
    {
        var ca = s.ToCharArray();
        Array.Reverse(ca);
        string t = new string(ca);
        return t;
    }

}

Вывод:

metsySgnikcarTcitamotuA -- Automatic Tracking System 


rotidELMX -- XML Editor 


looT0.2TLSXdnALMXnA -- An XML And XSLT 2.0 Tool 


sgnihTDCBAfOrebmuN -- Number Of ABCD Things 


naMdooGA -- A Good Man 


naMdooGAfOedoC -- Code Of A Good Man 

Он работает путем сканирования строки назад и превращения заглавной буквы в терминатор.Желая иметь параметр для RegEx для сканирования строки в обратном направлении, поэтому вышеописанное обращение строки не понадобится: -)

0 голосов
/ 23 июня 2010

Если вы хотите сохранить аббревиатуры без изменений, замените "([^ A-Z]) ([A-Z])" на "\ 1 \ 2", иначе замените "(.) ([A-Z])" на "\ 1 \ 2".

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