Как бы вы преобразовали имена в правильный регистр в С#?
У меня есть список имен, которые я хотел бы подтвердить.
Например: mcdonalds to McDonalds или o'brien to O'Brien.
Как бы вы преобразовали имена в правильный регистр в С#?
У меня есть список имен, которые я хотел бы подтвердить.
Например: mcdonalds to McDonalds или o'brien to O'Brien.
Нет абсолютно никакого способа, чтобы компьютер просто знал, что первый "D" в "Макдональдс" должен быть капитализирован. Итак, я думаю, что есть два варианта.
У кого-то там может быть часть программного обеспечения или библиотека, которая сделает это за вас.
Запрет на то, что ваш единственный выбор заключается в следующем: во-первых, я бы поискал имя в словаре слов, имеющих "интересную" капитализацию. Очевидно, вам придется предоставить этот словарь самостоятельно, если он уже не существует. Во-вторых, примените алгоритм, который исправляет некоторые из очевидных, такие как кельтские имена, начинающиеся с O 'и Mac и Mc, хотя при наличии достаточно большого пула имен такой алгоритм, несомненно, будет иметь множество ложных срабатываний. И наконец, запишите первую букву каждого имени, которая не соответствует первым двум критериям.
Вы можете использовать поисковую систему, чтобы помочь вам. Отправьте запрос и посмотрите, как результаты заглавные буквы.
Я написал следующие методы расширения. Не стесняйтесь использовать их.
public static class StringExtensions
{
public static string ToProperCase( this string original )
{
if( original.IsNullOrEmpty() )
return original;
string result = _properNameRx.Replace( original.ToLower( CultureInfo.CurrentCulture ), HandleWord );
return result;
}
public static string WordToProperCase( this string word )
{
if( word.IsNullOrEmpty() )
return word;
if( word.Length > 1 )
return Char.ToUpper( word[0], CultureInfo.CurrentCulture ) + word.Substring( 1 );
return word.ToUpper( CultureInfo.CurrentCulture );
}
private static readonly Regex _properNameRx = new Regex( @"\b(\w+)\b" );
private static readonly string[] _prefixes = { "mc" };
private static string HandleWord( Match m )
{
string word = m.Groups[1].Value;
foreach( string prefix in _prefixes )
{
if( word.StartsWith( prefix, StringComparison.CurrentCultureIgnoreCase ) )
return prefix.WordToProperCase() + word.Substring( prefix.Length ).WordToProperCase();
}
return word.WordToProperCase();
}
}
Это интересная проблема. Я не думаю, что есть решение "из коробки".
Я добавил в закладки следующую статью, которая может быть близка к тому, что вы хотите:
Я не пробовал код, и это решение в значительной степени требует ручной обработки всех случаев. Но это начало, и, возможно, вы найдете его полезным.
Жесткая часть этого - это алгоритмы для выбора капитализации. Сама манипуляция строкой довольно проста. Не существует идеального способа, поскольку нет "правил" для случаев. Одной из стратегий может быть набор правил, таких как "заглавные буквы первой буквы... обычно" и "заглавные буквы третьей буквы, если первые две буквы являются mc... обычно"
Запуск со словарем реальных имен и сравнение их с вашим собственным именем для совпадений поможет. Вы также можете взять словарь реальных имен, создать цепочку Мархова и нарисовать любые новые имена в цепочке Мархова, чтобы определить капитализацию. Это безумное, сложное решение.
Идеальное решение - использовать людей для исправления данных.
Для этого требуется, чтобы ваша программа могла интерпретировать английский язык в определенной степени. По крайней мере, можно разбить строку на множество слов. В .NET Framework нет API-интерфейса, который может достичь этого.
Однако, если бы это было возможно, вы могли бы использовать следующий код.
public string ProperCase(string str, Func<string,bool> isWord) {
var word = new StringBuilder();
var cur = new StringBuilder();
for ( var i = 0; i < str.Length; i++ ) {
cur.Append(cur.Length == 0 ? Char.ToUpper(str[i]) : str[i]));
if ( isWord(cur.ToString()) {
word.Append(cur.ToString());
cur.Length = 0;
}
}
if ( cur.Length > 0 ) {
word.Append(cur);
}
return word.ToString();
}
Это не идеальное решение, но оно дает вам общее представление о схеме
Вы можете проверить фамилию нижнего/смешанного случая на словарь (файл), в котором есть правильные оболочки, а затем вернуть "реальное" значение из словаря.
У меня был быстрый google, чтобы узнать, существует ли он, но безрезультатно!
CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
TextInfo textInfo = cultureInfo.TextInfo;
string txt = textInfo.ToTitleCase("texthere");
Я планирую написать такую функцию, но, вероятно, не перейду к слишком большому количеству случаев... Ниже в psuedo-коде с регулярным выражением для сопоставления...
начните с /\ b [A-Z] +\b/в соответствии с установленным соответствием, поэтому каждая последовательность букв по границе слова совпадает с набором.
if the string is all uppercase...
lower-case the string
upper-case the first letter
do the following beginning of string replacements
Vanb -> VanB
Vanh -> VanH
Mc? -> Mc? (uppercase wildcard character)
Mac[^kh] -> Mac? (uppercase wildcard match)
С замененной цельной строкой имя соответствует сопоставлению с другими наборами замены, например...
"De La " -> "de la "
Это должно уловить большинство случаев для имен в частности... но хорошая база данных с общими именами будет очень приятной.
Вот мое решение. Это жестко закодирует имена в программе, но с небольшой работой вы можете сохранить текстовый файл вне программы и прочитать в исключениях имени (т.е. Van, Mc, Mac) и пройти через них.
public static String toProperName(String name)
{
if (name != null)
{
if (name.Length >= 2 && name.ToLower().Substring(0, 2) == "mc") // Changes mcdonald to "McDonald"
return "Mc" + Regex.Replace(name.ToLower().Substring(2), @"\b[a-z]", m => m.Value.ToUpper());
if (name.Length >= 3 && name.ToLower().Substring(0, 3) == "van") // Changes vanwinkle to "VanWinkle"
return "Van" + Regex.Replace(name.ToLower().Substring(3), @"\b[a-z]", m => m.Value.ToUpper());
return Regex.Replace(name.ToLower(), @"\b[a-z]", m => m.Value.ToUpper()); // Changes to title case but also fixes
// appostrophes like O'HARE or o'hare to O'Hare
}
return "";
}