Как сделать заглавными первую букву имени и фамилии в C #?

141

Есть ли простой способ сделать первую букву строки заглавной, а остальную часть уменьшить? Есть ли встроенный метод или мне нужно сделать свой собственный?

Майк Роза
источник
3
Я ничего не знаю о вашем конкретном приложении, но думаю, нужно сделать общее предупреждение: программисты не должны волей-неволей применять этот метод к реальным именам. Я думаю, старик Джон Макдональд был бы расстроен, если бы этот метод исказил свое имя, не говоря уже о ее каммингах, колокольчиках, данах бойд, 行 弘, людях с "фон" в фамилии, людях с фамилией "О'Дойл" и т. д., т. д. и т. д. Большинство имен имеют формат, отличный от "First Last" с такими заглавными буквами (и с заглавными буквами); Рекомендую прочитать kalzumeus.com/2010/06/17/…
Nick
@Nick абсолютно прав. Вы даже не можете предположить, что нижний регистр, сопровождаемый прописными, неверен - ирландские имена делают такие вещи, как «Ó hAirt». Предположите, что для любого соглашения, которое вы можете придумать, найдется культура / язык, которые вас удивят.
Джеймс Мур

Ответы:

259

TextInfo.ToTitleCase()делает первый символ в каждом токене строки заглавным.
Если нет необходимости поддерживать верхний регистр аббревиатуры, вы должны включить ToLower().

string s = "JOHN DOE";
s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s.ToLower());
// Produces "John Doe"

Если CurrentCulture недоступен, используйте:

string s = "JOHN DOE";
s = new System.Globalization.CultureInfo("en-US", false).TextInfo.ToTitleCase(s.ToLower());

См. Ссылку MSDN для подробного описания.

Ageektrapped
источник
24
Следует отметить, что это не работает, если строка состоит только из заглавных букв. Он считает, что все заглавные буквы - это аббревиатура.
Майк Руса,
9
Я видел со многими из них то, что на них нельзя положиться. Это не сработает, если имя будет чем-то вроде Маккейна или если вы начнете набирать больше иностранных имен.
Майк Уиллс,
25
@roosa - простое исправление для этого ToTitleCase (val.ToLower ())
Simon_Weaver
+1 Я знал, что это уже должно быть в FCL, и Google привел меня сюда = D
gideon
13
В отличие от ответа Натана ниже, я получаю сообщение об ошибке: «К сожалению, для нестатического поля, метода или свойства требуется ссылка на объект .......».
Dan W
117
CultureInfo.CurrentCulture.TextInfo.ToTitleCase("hello world");
Натан Баулч
источник
Ой, хватка! Хороший ответ. Я всегда забываю о глобализации.
Майкл Харен,
Отличное решение! В VB.Net:sItem = Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(sItem.ToLower) 'first char upper case
Nasenbaer
Вам необходимо определить культуру каждого отдельного имени , а не текущую культуру. Это не работает с именами.
Джеймс Мур,
1
Поскольку это опирается на CurrentCulture, как мы можем быть уверены, что нет культуры, которая относилась бы к этому иначе?
Руди
30
String test = "HELLO HOW ARE YOU";
string s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(test);

Приведенный выше код не работает .....

поэтому поместите приведенный ниже код, конвертируя в нижний, затем примените функцию

String test = "HELLO HOW ARE YOU";
string s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(test.ToLower());
Ганешан СуббьяхПандийский
источник
15

Есть некоторые случаи, с которыми CultureInfo.CurrentCulture.TextInfo.ToTitleCaseневозможно справиться, например: апостроф '.

string input = CultureInfo.CurrentCulture.TextInfo.ToTitleCase("o'reilly, m'grego, d'angelo");
// input = O'reilly, M'grego, D'angelo

Регулярное выражение может также использоваться , \b[a-zA-Z]чтобы определить начальный символ слова после того, как границ слова \b, то нам нужно просто заменить матч на его верхнем благодаря случаю эквивалентности к Regex.Replace(string input,string pattern,MatchEvaluator evaluator)методу:

string input = "o'reilly, m'grego, d'angelo";
input = Regex.Replace(input.ToLower(), @"\b[a-zA-Z]", m => m.Value.ToUpper());
// input = O'Reilly, M'Grego, D'Angelo

Регулярное выражение может быть настроено при необходимости, например, если мы хотим , чтобы обрабатывать MacDonaldи McFryслучаи регулярного выражения становится:(?<=\b(?:mc|mac)?)[a-zA-Z]

string input = "o'reilly, m'grego, d'angelo, macdonald's, mcfry";
input = Regex.Replace(input.ToLower(), @"(?<=\b(?:mc|mac)?)[a-zA-Z]", m => m.Value.ToUpper());
// input = O'Reilly, M'Grego, D'Angelo, MacDonald'S, McFry

Если нам нужно обрабатывать несколько префиксов нам нужно только изменить группу (?:mc|mac), например , добавить французские префиксы du, de: (?:mc|mac|du|de).

Наконец, мы можем понять, что это регулярное выражение также будет соответствовать регистру MacDonald'Sпоследнего, 'sпоэтому нам нужно обработать его в регулярном выражении с отрицательным взглядом назад (?<!'s\b). В итоге имеем:

string input = "o'reilly, m'grego, d'angelo, macdonald's, mcfry";
input = Regex.Replace(input.ToLower(), @"(?<=\b(?:mc|mac)?)[a-zA-Z](?<!'s\b)", m => m.Value.ToUpper());
// input = O'Reilly, M'Grego, D'Angelo, MacDonald's, McFry
Polkduran
источник
@polkduran Я изо всех сил пытаюсь найти способ справиться с римскими цифрами в конце имени; Я хотел бы сделать их все прописными: Джон Смит III. Будет ли этому мешать отрицательный взгляд назад?
Мэтт
Как обычно, я наконец смог ответить на свой вопрос. Я добавил необязательную группу для сопоставления римских цифр (которые будут в верхнем регистре). Вот полное регулярное выражение, которое я использую сейчас: (? <= \ B (?: Mc | mac)?) [A-zA-Z] (? <! 'S \ b) (?: ii | iii | iv | v | vi | vii | viii | ix)?
Мэтт
Ваш случай особенный, регулярное выражение в ответе обрабатывает каждое имя (фамилию) как отдельное слово во входной строке (тестовая входная строка имеет несколько имен), поэтому в нем нет понятия «конец имени» . Если вы рассматриваете входную строку как одно имя, вы можете префикс регулярного выражения с помощью простого условия для вашего случая: \b[ivxlcdm]+$|так что у вас есть \b[ivxlcdm]+$|(?<=\b(?:mc|mac)?)[a-zA-Z](?<!'s\b). Это приведет к тому, что все конечные слова имени, имеющего нестрогий формат римских цифр ( ivxlcdm), будут заглавными . Однако у вас могут быть некоторые нежелательные результаты, например, «Li» станет «LI»
polkduran
Интересно. Я думаю, что ваше добавление, вероятно, более правильное в отношении структуры, но я согласен ... Я думаю, что будут некоторые проблемы, о которых вы говорили. В моем решении выше я жестко закодировал суффиксы до «ix», которые будут работать в моем случае, но я понимаю, что они могут не подходить для всех.
Мэтт
1
@ Si8, ты пробовал? Regex.Replace("JOHN DOE".ToLower(), @"(?<=\b(?:mc|mac)?)[a-zA-Z](?<!'s\b)", m => m.Value.ToUpper())
polkduran
7

Mc и Mac - распространенные префиксы фамилий в США, есть и другие. TextInfo.ToTitleCase не обрабатывает эти случаи и не должен использоваться для этой цели. Вот как я это делаю:

    public static string ToTitleCase(string str)
    {
        string result = str;
        if (!string.IsNullOrEmpty(str))
        {
            var words = str.Split(' ');
            for (int index = 0; index < words.Length; index++)
            {
                var s = words[index];
                if (s.Length > 0)
                {
                    words[index] = s[0].ToString().ToUpper() + s.Substring(1);
                }
            }
            result = string.Join(" ", words);
        }
        return result;
    }
Джейми Иде
источник
4

Самым прямым вариантом будет использование функции ToTitleCase , доступной в .NET, которая должна большую часть времени заботиться об имени. Как указал edg , есть некоторые имена, для которых это не сработает, но они довольно редки, поэтому, если вы не ориентируетесь на культуру, где такие имена распространены, нет необходимости в чем-то, о чем вам нужно слишком беспокоиться.

Однако, если вы не работаете с .NET langauge, это зависит от того, как выглядит ввод - если у вас есть два отдельных поля для имени и фамилии, тогда вы можете просто использовать первую букву с заглавной буквы, уменьшив остальную часть, используя подстроки.

firstName = firstName.Substring(0, 1).ToUpper() + firstName.Substring(1).ToLower();
lastName = lastName.Substring(0, 1).ToUpper() + lastName.Substring(1).ToLower();

Однако, если вам предоставлено несколько имен как часть одной и той же строки, вам необходимо знать, как вы получаете информацию, и соответствующим образом разделить ее . Итак, если вы получили имя типа «Джон Доу», вы разбиваете строку на основе символа пробела. Если он находится в таком формате, как «Доу, Джон», вам нужно будет разделить его по запятой. Однако, как только вы его разделите, вы просто примените код, показанный ранее.

rjzii
источник
3

CultureInfo.CurrentCulture.TextInfo.ToTitleCase («мое имя»);

возвращает ~ Мое имя

Но проблема с такими именами, как McFly, как говорилось ранее, все еще существует.

Дэвид С
источник
3
Макфрай! Коничива, мистер Фугицу-сан
Ян Бойд
@David C Попробуйте заменить пробел на ноль !! как string.replace ('', '')
Чинтан
3

Я использую свой собственный метод, чтобы исправить это:

Например, фраза: «привет, мир. Привет, это мир stackoverflow». будет "Hello World. Hello This Is The Stackoverflow World.". Регулярное выражение \ b (начало слова) \ w (первый символ слова) подойдет.

/// <summary>
/// Makes each first letter of a word uppercase. The rest will be lowercase
/// </summary>
/// <param name="Phrase"></param>
/// <returns></returns>
public static string FormatWordsWithFirstCapital(string Phrase)
{
     MatchCollection Matches = Regex.Matches(Phrase, "\\b\\w");
     Phrase = Phrase.ToLower();
     foreach (Match Match in Matches)
         Phrase = Phrase.Remove(Match.Index, 1).Insert(Match.Index, Match.Value.ToUpper());

     return Phrase;
}
Тон Сной
источник
2

Предложения по использованию ToTitleCase не будут работать для строк, которые все в верхнем регистре. Таким образом, вам нужно будет вызвать ToUpper для первого символа и ToLower для остальных символов.

Тундей
источник
6
Почему бы не вызвать ToLower во входной строке перед вызовом ToTitleCase?
Энди Роуз,
2

Этот класс делает свое дело. Вы можете добавлять новые префиксы к статическому строковому массиву _prefixes .

public static class StringExtensions
{
        public static string ToProperCase( this string original )
        {
            if( String.IsNullOrEmpty( original ) )
                return original;

            string result = _properNameRx.Replace( original.ToLower( CultureInfo.CurrentCulture ), HandleWord );
            return result;
        }

        public static string WordToProperCase( this string word )
        {
            if( String.IsNullOrEmpty( word ) )
                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();
        }
}
Эдди Веласкес
источник
1

Если вы используете vS2k8, вы можете использовать метод расширения, чтобы добавить его в класс String:

public static string FirstLetterToUpper(this String input)
{
    return input = input.Substring(0, 1).ToUpper() + 
       input.Substring(1, input.Length - 1);
}
FlySwat
источник
9
Char.ToUpper(input[0]) + input.Substring(1)ИМХО читабельнее.
Хосам Али,
ИМХО input.FirstLetterToUpper(), конечно , более читаемым против Char.ToUpper(input[0]) + input.Substring(1), но менее прозрачным
Michael
0

Чтобы обойти некоторые из выделенных проблем / проблем, я бы предложил сначала преобразовать строку в нижний регистр, а затем вызвать метод ToTitleCase. Затем вы можете использовать IndexOf («Mc») или IndexOf («O \ '») для определения особых случаев, требующих более конкретного внимания.

inputString = inputString.ToLower();
inputString = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(inputString);
int indexOfMc = inputString.IndexOf(" Mc");
if(indexOfMc  > 0)
{
   inputString.Substring(0, indexOfMc + 3) + inputString[indexOfMc + 3].ToString().ToUpper() + inputString.Substring(indexOfMc + 4);
}
Энди Роуз
источник
0

Мне так нравится:

using System.Globalization;
...
TextInfo myTi = new CultureInfo("en-Us",false).TextInfo;
string raw = "THIS IS ALL CAPS";
string firstCapOnly = myTi.ToTitleCase(raw.ToLower());

Снято из этой статьи MSDN .

TrentVB
источник
0

Надеюсь, это тебе поможет.

String fName = "firstname";
String lName = "lastname";
String capitalizedFName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(fName);
String capitalizedLName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(lName);
Арун
источник
0
 public static string ConvertToCaptilize(string input)
        {
            if (!string.IsNullOrEmpty(input))
            {
                string[] arrUserInput = input.Split(' ');


                // Initialize a string builder object for the output
                StringBuilder sbOutPut = new StringBuilder();


                // Loop thru each character in the string array
                foreach (string str in arrUserInput)
                {
                    if (!string.IsNullOrEmpty(str))
                    {
                        var charArray = str.ToCharArray();
                        int k = 0;
                        foreach (var cr in charArray)
                        {
                            char c;
                            c = k == 0 ? char.ToUpper(cr) : char.ToLower(cr);
                            sbOutPut.Append(c);
                            k++;
                        }


                    }
                    sbOutPut.Append(" ");
                }
                return sbOutPut.ToString();
            }
            return string.Empty;

        }
Говинд Сингх Рават
источник
-1

Как указано в edg, вам понадобится более сложный алгоритм для обработки специальных имен (вероятно, поэтому многие места переводят все в верхний регистр).

Что-то вроде этого непроверенного С # должно обрабатывать запрошенный вами простой случай:

public string SentenceCase(string input)
{
    return input(0, 1).ToUpper + input.Substring(1).ToLower;
}
Майкл Харен
источник
Забудьте об этом - используйте класс глобализации stackoverflow.com/questions/72831/…
Майкл Харен