Преобразование CamelCase в дружественное имя, то есть константы Enum; Проблемы?

В моем ответе на этот вопрос я упомянул, что мы использовали синтаксический анализ UpperCamelCase, чтобы получить описание константы перечисления, не украшенного атрибутом Description, но это было наивно, и он не работал во всех случаях. Я пересмотрел его, и вот что я придумал:

var result = Regex.Replace(camelCasedString, 
                            @"(?<a>(?<!^)[A-Z][a-z])", @" ${a}");
result = Regex.Replace(result,
                            @"(?<a>[a-z])(?<b>[A-Z0-9])", @"${a} ${b}");

Первый Заменить ищет букву в верхнем регистре, за которой следует строчная буква, EXCEPT, где заглавная буква - это начало строки (во избежание возврата назад и обрезки) и добавляет предыдущее пространство. Он обрабатывает ваши базовые идентификаторы UpperCamelCase и ведет все верхние аббревиатуры, такие как FDICInsured.

Второй Replace ищет строчную букву, за которой следуют прописная буква или число, и вставляет пробел между ними. Это относится к особым, но общим случаям средних или конечных аббревиатур или номеров в идентификаторе (за исключением ведущих номеров, которые в любом случае запрещены в языках C-стиля).

Выполняя некоторые базовые модульные тесты, комбинация этих двух правильно разделяет все следующие идентификаторы: NoDescription, HasLotsOfWords, AAANoDescription, ThisHasTheAcronymABCInTheMiddle, MyTrailingAcronymID, TheNumber3, IDo3Things, IAmAValueWithSingleLetterWords и Basic (в которых не было добавленных пробелов).

Итак, я публикую это первым, чтобы поделиться им с другими, которые могут найти это полезным, и, во-вторых, задать два вопроса:

  • Кто-нибудь видит случай, который будет следовать общим соглашениям CamelCase-ish, которые НЕ ДОЛЖНЫ быть правильно разделены на дружественную строку таким образом? Я знаю, что он не будет разделять смежные аббревиатуры (FDICFCUAInsured), рекапитализировать "правильно" аббревиатуры camelCased, такие как FdicInsured, или использовать первую букву нижнего индекса CamelCased (но это легко добавить - result = Regex.Replace(result, "^[a-z]", m=>m.ToString().ToUpper());). Что-нибудь еще?

  • Может ли кто-нибудь увидеть способ сделать это одно утверждение или более изящным? Я пытался комбинировать вызовы Replace, но поскольку они выполняют две разные вещи в своих совпадениях, это не может быть сделано с этими двумя строками. Они могут быть объединены в цепочку методов с использованием метода расширения RegexReplace на String, но может ли кто-нибудь лучше подумать?

Ответ 1

Итак, хотя я согласен с Хансом Пассансом здесь, я должен сказать, что мне пришлось попробовать свои силы, сделав его одним регулярным выражением в качестве пользователя регулярного выражения кресла.

(?<a>(?<!^)((?:[A-Z][a-z])|(?:(?<!^[A-Z]+)[A-Z0-9]+(?:(?=[A-Z][a-z])|$))|(?:[0-9]+)))

Это то, что я придумал. Кажется, все те тесты, которые вы задали в вопросе, проходят.

So

var result = Regex.Replace(camelCasedString, @"(?<a>(?<!^)((?:[A-Z][a-z])|(?:(?<!^[A-Z]+)[A-Z0-9]+(?:(?=[A-Z][a-z])|$))|(?:[0-9]+)))", @" ${a}");

Делает это за один проход.

Ответ 2

не то, что это напрямую отвечает на вопрос, но почему бы не попробовать, взяв стандартный С# API и преобразовать каждый класс в дружественное имя? Это потребует некоторой ручной проверки, но это даст вам хороший список стандартных имен для тестирования.

Ответ 3

Скажем, каждый случай, с которым вы сталкиваетесь, работает с этим (вы спрашиваете нас о примерах, которые не будут, а затем дадут нам, поэтому у вас даже не осталось вопросов).

Это все еще связывает пользовательский интерфейс с программными идентификаторами таким образом, чтобы изменения в программировании и пользовательском интерфейсе были хрупкими.

По-прежнему предполагается, что ваша программа будет использоваться только на одном языке. Либо ваш потенциальный рынок настолько мал, что просто индексирование массива имен будет достаточно масштабируемым (например, индивидуальный заказ или собственный проект), или вы предполагаете, что никогда не будете достаточно успешными, чтобы быть доступным для других языков или других диалектов вашего первого выбранного языка.

"Хорошо, он будет работать до тех пор, пока мы провалимся", звучит как прохождение оценки в балансирующих проектах?

Либо закодируйте его, чтобы использовать ресурсы, либо закодируйте его, чтобы передать имя перечисления вслепую или использовать массив имен, поскольку это по крайней мере будет изменяться впоследствии.