Регулярное выражение, разделите строку заглавной буквой, но игнорируйте TLA
Я использую регулярное выражение
System.Text.RegularExpressions.Regex.Replace(stringToSplit, "([A-Z])", " $1").Trim()
разделять строки заглавной буквой, например:
"MyNameIsSimon" становится "Мое имя - это Симон"
Я считаю это невероятно полезным при работе с перечислениями. То, что я хотел бы сделать, это немного изменить его, чтобы строки были разделены только в том случае, если следующая буква является строчной буквой, например:
"USAToday" станет 'USA Today'
Можно ли это сделать?
EDIT: Спасибо всем за ответ. Возможно, я не мог полностью подумать об этом, в некоторых случаях "A" и "I" нужно было бы игнорировать, но это невозможно (по крайней мере, не в значимом смысле). В моем случае, хотя ответы ниже делают то, что мне нужно. Спасибо!
Ответы
Ответ 1
((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))
или его двоюродный брат с поддержкой Unicode
((?<=\p{Ll})\p{Lu}|\p{Lu}(?=\p{Ll}))
если глобально заменить на
" $1"
ручки
TodayILiveInTheUSAWithSimon
USAToday
IAmSOOOBored
получая
Today I Live In The USA With Simon
USA Today
I Am SOOO Bored
На втором шаге вам придется обрезать строку.
Ответ 2
любой символ верхнего регистра, за которым не следует символ верхнего регистра:
Replace(string, "([A-Z])(?![A-Z])", " $1")
Edit:
Я только заметил, что вы используете это для перечислений. Я действительно не поощряю использование строковых представлений перечислений, подобных этому, и проблемы, стоящие перед вами, являются хорошей причиной. Посмотрите на это вместо этого:
http://www.refactoring.com/catalog/replaceTypeCodeWithClass.html
Ответ 3
Вы можете подумать об изменении перечислений; Руководства по кодированию MS предлагают Паскаль обрезать аббревиатуры, как если бы они были словами; XmlDocument
, HtmlWriter
и т.д. Двухбуквенные акрионимы не следуют этому правилу; System.IO
.
Итак, вы должны использовать UsaToday
, и ваша проблема исчезнет.
Ответ 4
выражение Томалака работало для меня, но не со встроенной функцией Replace
. Regex.Replace()
, однако, действительно работал.
For i As Integer = 0 To names.Length - 1
'Worked
names(i) = Regex.Replace(names(i), "((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))", " $1").TrimStart()
' Didn't work
'names(i) = Replace(names(i), "([A-Z])(?=[a-z])|(?<=[a-z])([A-Z])", " $1").TrimStart()
Next
Кстати, я использую это, чтобы разделить слова в именах перечислений для отображения в пользовательском интерфейсе и прекрасно работает.
Ответ 5
Примечание. Я недостаточно хорошо читал вопрос, USAToday вернется "Сегодня"; поэтому этот anwser не является правильным.
public static List<string> SplitOnCamelCase(string text)
{
List<string> list = new List<string> ();
Regex regex = new Regex(@"(\p{Lu}\p{Ll}+)");
foreach (Match match in regex.Matches(text))
{
list.Add (match.Value);
}
return list;
}
Это будет соответствовать "WakeOnBoot" как "Wake On Boot" и ничего не возвращает в NMI или TLA
Ответ 6
Моя версия, которая также обрабатывает простые арифметические выражения:
private string InjectSpaces(string s)
{
var patterns = new string[] {
@"(?<=[^A-Z,&])[A-Z]", // match capital preceded by any non-capital except ampersand
@"(?<=[A-Z])[A-Z](?=[a-z])", // match capital preceded by capital and followed by lowercase letter
@"[\+\-\*\/\=]", // match arithmetic operators
@"(?<=[\+\-\*\/\=])[0-9,\(]" // match 0-9 or open paren preceded by arithmetic operator
};
var pattern = $"({string.Join("|", patterns)})";
return Regex.Replace(s, pattern, " $1");
}