Подтвердить что ты не робот

Регулярное выражение: конвертируйте верблюжниковый футляр на все колпачки с символами подчеркивания

Какое регулярное выражение может использоваться для следующих преобразований?

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
4b9b3361

Ответ 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()