ToPascalCase() C# для всех заглавных букв Сокращения
Я использую ReSharper и пытаюсь соблюдать правила по умолчанию.
В части моего кода мне нужно изменить строковое свойство на PascalCase.
Я пробовал многочисленные методы, но не могу найти тот, который работает для вещей, которые включают все заглавные сокращения.
EX:
MPSUser --> Still MPSUser (should be MpsUser)
ArticleID --> Still Article ID (Should be ArticleId)
closeMethod --> Works and changes to CloseMethod
Может кто-нибудь помочь мне создать метод, который может превратить любую строку в PascalCase? Спасибо!
2 ответа
Единственный известный мне встроенный метод для преобразования в PascalCase
является TextInfo.ToTitleCase
, и он не обрабатывает все заглавные буквы по замыслу. Чтобы обойти это, я создал собственное регулярное выражение, которое может обнаружить все части слова, а затем они по отдельности преобразуются в регистр заглавия / паскаля:
string ToPascalCase(string s)
{
// Find word parts using the following rules:
// 1. all lowercase starting at the beginning is a word
// 2. all caps is a word.
// 3. first letter caps, followed by all lowercase is a word
// 4. the entire string must decompose into words according to 1,2,3.
// Note that 2&3 together ensure MPSUser is parsed as "MPS" + "User".
var m = Regex.Match(s, "^(?<word>^[a-z]+|[A-Z]+|[A-Z][a-z]+)+$");
var g = m.Groups["word"];
// Take each word and convert individually to TitleCase
// to generate the final output. Note the use of ToLower
// before ToTitleCase because all caps is treated as an abbreviation.
var t = Thread.CurrentThread.CurrentCulture.TextInfo;
var sb = new StringBuilder();
foreach (var c in g.Captures.Cast<Capture>())
sb.Append(t.ToTitleCase(c.Value.ToLower()));
return sb.ToString();
}
Эта функция должна обрабатывать общие случаи использования:
s | ToPascalCase(s)
MPSUser | MpsUser
ArticleID | ArticleId
closeMethod | CloseMethod
Я много позаимствовал из решения Мелламокба, чтобы придумать что-то более всеобъемлющее. Например, я хотел оставить цифры в покое. Кроме того, я хотел, чтобы в качестве разделителя использовался любой не буквенный, не числовой символ. Вот:
public static string ToPascalCase(this string s) {
var result = new StringBuilder();
var nonWordChars = new Regex(@"[^a-zA-Z0-9]+");
var tokens = nonWordChars.Split(s);
foreach (var token in tokens) {
result.Append(PascalCaseSingleWord(token));
}
return result.ToString();
}
static string PascalCaseSingleWord(string s) {
var match = Regex.Match(s, @"^(?<word>\d+|^[a-z]+|[A-Z]+|[A-Z][a-z]+|\d[a-z]+)+$");
var groups = match.Groups["word"];
var textInfo = Thread.CurrentThread.CurrentCulture.TextInfo;
var result = new StringBuilder();
foreach (var capture in groups.Captures.Cast<Capture>()) {
result.Append(textInfo.ToTitleCase(capture.Value.ToLower()));
}
return result.ToString();
}
Вот x-unit test, который показывает некоторые тестовые случаи:
[Theory]
[InlineData("imAString", "ImAString")]
[InlineData("imAlsoString", "ImAlsoString")]
[InlineData("ImAlsoString", "ImAlsoString")]
[InlineData("im_a_string", "ImAString")]
[InlineData("im a string", "ImAString")]
[InlineData("ABCAcronym", "AbcAcronym")]
[InlineData("im_a_ABCAcronym", "ImAAbcAcronym")]
[InlineData("im a ABCAcronym", "ImAAbcAcronym")]
[InlineData("8ball", "8Ball")]
[InlineData("im a 8ball", "ImA8Ball")]
[InlineData("IM_ALL_CAPS", "ImAllCaps")]
[InlineData("IM ALSO ALL CAPS", "ImAlsoAllCaps")]
[InlineData("i-have-dashes", "IHaveDashes")]
[InlineData("a8word_another_word", "A8WordAnotherWord")]
public void WhenGivenString_ShouldPascalCaseIt(string input, string expectedResult) {
var result = input.ToPascalCase();
Assert.Equal(expectedResult, result);
}