Регулярное выражение: конвертируйте верблюжниковый футляр на все колпачки с символами подчеркивания
Какое регулярное выражение может использоваться для следующих преобразований?
City -> CITY
FirstName -> FIRST_NAME
DOB -> DOB
PATId -> PAT_ID
RoomNO -> ROOM_NO
Следующие почти работы - это просто добавляет дополнительное подчеркивание к началу слова:
var rgx = @"(?x)( [A-Z][a-z,0-9]+ | [A-Z]+(?![a-z]) )";
var tests = new string[] { "City",
"FirstName",
"DOB",
"PATId",
"RoomNO"};
foreach (var test in tests)
Console.WriteLine("{0} -> {1}", test,
Regex.Replace(test, rgx, "_$0").ToUpper());
// output:
// City -> _CITY
// FirstName -> _FIRST_NAME
// DOB -> _DOB
// PATId -> _PAT_ID
// RoomNO -> _ROOM_NO
Ответы
Ответ 1
Из-за идеи Джона М Ганта добавить символы подчеркивания, а затем заглавные буквы, я думаю, что это регулярное выражение должно работать:
([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])
заменяя:
$1$3_$2$4
Вы можете переименовать зоны захвата, чтобы заменить строку замены немного приятнее для чтения. Только $1 или $3 должны иметь значение, то же самое с $2 и $4. Общая идея состоит в том, чтобы добавить символы подчеркивания, когда:
- Есть две заглавные буквы, за которыми следует строчная буква, поместите подчеркивание между двумя прописными буквами. (PATId → PAT_Id)
- Есть маленькая буква, за которой следует заглавная буква, поместите знак подчеркивания в середине двух. (RoomNO → Room_NO и FirstName → First_Name)
Надеюсь, что это поможет.
Ответ 2
Я предлагаю простое Regex для вставки подчеркивания, а затем string.ToUpper()
для преобразования в верхний регистр.
Regex.Replace(test, @"(\p{Ll})(\p{Lu})", "$1_$2").ToUpper()
Это две операции вместо одной, но для меня ее намного легче читать, чем заменить одно большое сложное регулярное выражение.
Ответ 3
Я могу, вероятно, создать регулярное выражение, которое будет делать это... но я считаю, что преобразование регулярного выражения может быть неправильным ответом. Я предлагаю вам взять то, что у вас уже есть, и просто отрубить первый символ (главный подчеркивание) с выхода. Время CPU, вероятно, будет таким же или менее таким, и ваше время кодирования будет несущественным.
Попробуйте: (?x)(.)( [A-Z][a-z,0-9]+ | [A-Z]+(?![a-z]) )
и измените код, чтобы вывести $0_ $1 вместо _ $0 < - misguided и не удалось попытаться понять, что я сказал, это глупая идея.
Ответ 4
Похоже, что Rails делает это с использованием более чем одного регулярного выражения.
var rgx = @"([A-Z]+)([A-Z][a-z])";
var rgx2 = @"([a-z\d])([A-Z])";
foreach (var test in tests)
{
var result = Regex.Replace(test, rgx, "$1_$2");
result = Regex.Replace(result, rgx2, "$1_$2");
result = result.ToUpper();
Console.WriteLine("{0} -> {1}", test, result);
}
Ответ 5
Я понимаю, что это старый вопрос, но он все еще часто возникает, поэтому я решил поделиться своим собственным подходом.
Вместо того, чтобы пытаться сделать это с заменой, идея состоит в том, чтобы найти все "слова" в строке и затем преобразовать их в верхний регистр и присоединиться:
var tests = new string[] { "City",
"FirstName",
"DOB",
"PATId",
"RoomNO"};
foreach (var test in tests)
Console.WriteLine("{0} -> {1}", test,
String.Join("_", new Regex(@"^(\p{Lu}(?:\p{Lu}*|[\p{Ll}\d]*))*$")
.Match(test)
.Groups[1]
.Captures
.Cast<Capture>()
.Select(c => c.Value.ToUpper())));
Не очень краткий, но позволяет сосредоточиться на определении того, что такое "слово", а не борьба с якорями, разделителями и еще много чего. В этом случае я определил слово как нечто, начинающееся с прописной буквы, следующей либо строкой заглавных букв, либо комбинацией строчных и прописных букв. Я мог бы захотеть разделить последовательности цифр. "^(\p{Lu}(?:\p{Lu}*|\p{Ll}*)|\d+)*$"
сделал бы трюк. Или, может быть, я хотел, чтобы цифры были частью предыдущего заглавного слова, тогда я бы сделал "^(\p{Lu}(?:[\p{Lu}\d]*|[\p{Ll}\d]*))*$"
.
Ответ 6
Здесь нет javascript-ответа, поэтому его можно также добавить.
(используется регулярное выражение @John McDonald)
var text = "fooBar barFoo";
var newText = text.replace(/([A-Z])([A-Z][a-z])|([a-z0-9])([A-Z])/g, "$1$3_$2$4");
newText.toLowerCase()