Мне нужно разобрать некоторые данные, и я хочу конвертировать
AutomaticTrackingSystem
к
Automatic Tracking System
по существу помещая пробел перед любой заглавной буквой (кроме первой, конечно)
Мне нужно разобрать некоторые данные, и я хочу конвертировать
AutomaticTrackingSystem
к
Automatic Tracking System
по существу помещая пробел перед любой заглавной буквой (кроме первой, конечно)
Без регулярного выражения вы можете сделать что-то вроде (или, возможно, что-то более сжатое с помощью 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
Вы можете использовать образы, например:
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]
Я только что написал функцию, чтобы сделать именно это.:)
Замените ([a-z])([A-Z])
на $1 $2
(или \1 \2
на других языках).
У меня также есть замена для ([A-Z]+)([A-Z][a-z])
тоже - это преобразует такие вещи, как "NumberOfABCDThings" в "Number Of ABCD Things"
Итак, в С# это выглядит примерно так:
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])
для первого матча.
Hmmm, другой способ записи этих регулярных выражений, используя lookbehind и lookahead, состоит в том, чтобы просто совместить позицию и вставить пробел - то есть (?<=[a-z])(?=[A-Z])
и (?<=[A-Z]+)(?=[A-Z][a-z])
, и в обоих случаях заменить просто "" - не уверены, есть ли могут быть преимуществами этого метода, но это интересный способ.:)
По-видимому, существует опция для обратного regex:-) Теперь мы можем устранить разворот строк, здесь другой способ сделать это:
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
Если вы хотите сохранить акронимы неповрежденными, замените "([^ A-Z]) ([A-Z]) на" \1\2 ", иначе замените "(.) ([A-Z])" на "\ 1\2".
Попробуйте следующее:
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 для сканирования строки назад, поэтому вышеописанная разворот строк больше не понадобится: -)
Просто используйте этот linq one-liner: (отлично работает для меня)
public static string SpaceCamelCase(string input)
{
return input.Aggregate(string.Empty, (old, x) => $"{old}{(char.IsUpper(x) ? " " : "")}{x}").TrimStart(' ');
}