Como faço para colocar em maiúscula a primeira letra do nome e sobrenome em C #?

141

Existe uma maneira fácil de colocar em maiúscula a primeira letra de uma string e diminuir o restante? Existe um método embutido ou preciso criar o meu?

Mike Roosa
fonte
3
Não sei nada sobre o seu aplicativo em particular, mas acho que é devido um aviso geral: os programadores não devem aplicar esse método, quer ou não, a nomes reais. Eu acho que o velho John MacDonald ficaria chateado com esse método, não mencionando ee cummings, ganchos de sino, danah boyd, 弘 行 弘, pessoas com um "von" no sobrenome, pessoas com o sobrenome "O'Doyle" , etc., etc., etc. A maioria dos nomes não tem o formato "Primeiro Último" com essa capitalização (e em caracteres maiúsculos); Eu recomendo ler kalzumeus.com/2010/06/17/…
Nick
@ Nick está absolutamente certo. Você não pode nem assumir que letras minúsculas seguidas de letras maiúsculas estão erradas - nomes irlandeses fazem coisas como "Ó hAirt". Suponha que, para qualquer convenção que você possa imaginar, haverá uma cultura / idioma que o surpreenderá.
James Moore

Respostas:

259

TextInfo.ToTitleCase()coloca em maiúscula o primeiro caractere em cada token de uma string.
Se não houver necessidade de manter a sigla Maiúsculas, inclua ToLower().

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

Se CurrentCulture estiver indisponível, use:

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

Consulte o link do MSDN para obter uma descrição detalhada.

ageektrapped
fonte
24
Uma coisa a ser observada aqui é que ela não funciona se a string for todas maiúscula. Pensa que todas as letras maiúsculas são um acrônimo.
Mike Roosa
9
O que eu vi com muitos deles é que você não pode confiar neles. Não funcionaria se o nome fosse parecido com McCain ou se você começar a encontrar mais nomes estrangeiros.
Mike Wills
25
@roosa - solução fácil para esse ToTitleCase (val.ToLower ())
Simon_Weaver
+1 Eu sabia que já deveria estar na FCL, e o Google me trouxe aqui = D
gideon
13
Diferentemente da resposta de Nathan abaixo, recebo um erro: "Uma referência a objeto é necessária para o campo, método ou propriedade não estática ......." infelizmente.
Dan W
117
CultureInfo.CurrentCulture.TextInfo.ToTitleCase("hello world");
Nathan Baulch
fonte
Aww snap! Boa resposta. Eu sempre esqueço as coisas da globalização.
Michael Haren
Ótima solução! Em VB.Net:sItem = Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(sItem.ToLower) 'first char upper case
Nasenbaer
Você precisa detectar a cultura de cada nome individual , não a cultura atual. Isso não funciona para nomes.
James Moore
1
Como isso depende do CurrentCulture, como podemos ter certeza de que não há cultura que lide com isso de maneira diferente?
Rudey
30
String test = "HELLO HOW ARE YOU";
string s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(test);

O código acima não funcionará .....

então coloque o código abaixo convertendo para lower e aplique a função

String test = "HELLO HOW ARE YOU";
string s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(test.ToLower());
Ganesan SubbiahPandian
fonte
15

Existem alguns casos que CultureInfo.CurrentCulture.TextInfo.ToTitleCasenão conseguem lidar, por exemplo: o apóstrofo '.

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

Um regex também pode ser usado \b[a-zA-Z]para identificar o caractere inicial de uma palavra após o limite de uma palavra \b; então, basta substituir a correspondência por sua equivalência em maiúsculas, graças ao Regex.Replace(string input,string pattern,MatchEvaluator evaluator)método:

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

A regex pode ser ajustado, se necessário, por exemplo, se quisermos lidar com os MacDonalde McFrycasos, o regex se torna:(?<=\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

Se precisamos lidar com mais prefixos só precisamos modificar o grupo (?:mc|mac), por exemplo, para adicionar prefixos francês du, de: (?:mc|mac|du|de).

Finalmente, podemos perceber que esse regex também corresponderá ao caso MacDonald'Santerior, 'spor isso precisamos lidar com ele no regex com um olhar negativo para trás (?<!'s\b). No final, temos:

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
fonte
@polkduran Estou lutando para encontrar uma maneira de lidar com algarismos romanos no final do nome; Eu gostaria de torná-los todos em maiúsculas: John Smith III. O olhar negativo por trás interferiria nisso?
Matt
Como costuma acontecer, finalmente pude responder minha própria pergunta. Adicionei um grupo opcional para combinar números romanos (que serão escritos em maiúsculas). Aqui está o regex completo que estou usando agora: (? <= \ B (?: Mc | mac)?) [A-zA-Z] (? <! 'S \ b) (?: ii | iii | iv | v | vi | vii | viii | ix)?
Matt
Seu caso é especial, o regex na resposta trata cada nome (sobrenome) como uma palavra isolada na sequência de entrada (a sequência de entrada de teste possui vários nomes), portanto, não possui a noção de 'fim do nome' . Se você tratar a sequência de entrada como um nome único, poderá prefixar o regex com uma condição simples para lidar com o seu caso: \b[ivxlcdm]+$|assim é \b[ivxlcdm]+$|(?<=\b(?:mc|mac)?)[a-zA-Z](?<!'s\b). Ele fará maiúsculas todas as palavras finais de um nome que tenha um formato de número romano não estrito ( ivxlcdm). No entanto, você pode ter resultados indesejados, por exemplo, 'Li' se tornará 'LI'
polkduran
Interessante. Acho que sua adição é provavelmente mais correta em relação à estrutura, mas concordo ... Acho que haverá alguns problemas que você declarou. Na minha solução acima, codifiquei os sufixos até "ix", que funcionarão no meu caso, mas reconheço que podem não ser adequados para todos.
Matt
1
@ Si8, você testou? Regex.Replace("JOHN DOE".ToLower(), @"(?<=\b(?:mc|mac)?)[a-zA-Z](?<!'s\b)", m => m.Value.ToUpper())
polkduran
7

Mc e Mac são prefixos de sobrenome comuns nos EUA, e existem outros. O TextInfo.ToTitleCase não trata desses casos e não deve ser usado para essa finalidade. Aqui está como eu estou fazendo isso:

    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;
    }
Jamie Ide
fonte
4

A opção mais direta será usar a função ToTitleCase disponível no .NET, que deve cuidar do nome na maioria das vezes. Como o edg apontou, existem alguns nomes para os quais ele não funcionará, mas esses são razoavelmente raros; portanto, a menos que você esteja direcionando uma cultura em que esses nomes sejam comuns, não é necessário algo com que você tenha que se preocupar muito.

No entanto, se você não estiver trabalhando com um idioma .NET, isso dependerá da aparência da entrada - se você tiver dois campos separados para o primeiro nome e o sobrenome, poderá colocar em maiúscula a primeira letra e diminuir o restante usando substrings.

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

No entanto, se você receber vários nomes como parte da mesma sequência, precisará saber como está obtendo as informações e dividi-las de acordo. Portanto, se você estiver recebendo um nome como "John Doe", divida a string com base no caractere de espaço. Se estiver em um formato como "Doe, John", será necessário dividi-lo com base na vírgula. No entanto, depois de dividir, basta aplicar o código mostrado anteriormente.

rjzii
fonte
3

CultureInfo.CurrentCulture.TextInfo.ToTitleCase ("meu nome");

retorna ~ Meu nome

Mas o problema ainda existe com nomes como McFly, como afirmado anteriormente.

David C
fonte
3
McFry! Konichiwa, Mr. Fugitsu-san
Ian Boyd
@ David C Tente substituir o espaço por nulo !! como string.replace ('', '')
Chintan
3

Eu uso meu próprio método para corrigir isso:

Por exemplo, a frase: "olá mundo. Olá, este é o mundo stackoverflow". será "Olá, mundo. Olá, este é o mundo do Stackoverflow". Regex \ b (início de uma palavra) \ w (primeiro caractere da palavra) fará o truque.

/// <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;
}
Ton Snoei
fonte
2

As sugestões para usar o ToTitleCase não funcionarão para seqüências de caracteres todas em maiúsculas. Então você precisará chamar o ToUpper no primeiro caractere e o ToLower nos caracteres restantes.

Tundey
fonte
6
Por que não chamar ToLower na string de entrada antes de chamar ToTitleCase?
Andy Rose
2

Esta classe faz o truque. Você pode adicionar novos prefixos à matriz de cadeias estáticas _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();
        }
}
Eddie Velasquez
fonte
1

Se você estiver usando o vS2k8, poderá usar um método de extensão para adicioná-lo à classe String:

public static string FirstLetterToUpper(this String input)
{
    return input = input.Substring(0, 1).ToUpper() + 
       input.Substring(1, input.Length - 1);
}
FlySwat
fonte
9
Char.ToUpper(input[0]) + input.Substring(1)é IMHO mais legível.
395 Hosam Aly
O IMHO input.FirstLetterToUpper()é certamente mais legível vs. Char.ToUpper(input[0]) + input.Substring(1), mas menos transparente #
Michael Michael
0

Para contornar alguns dos problemas / problemas que foram destacados, sugiro converter a string para minúscula primeiro e depois chamar o método ToTitleCase. Você pode usar IndexOf ("Mc") ou IndexOf ("O \ '") para determinar casos especiais que precisam de atenção mais específica.

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);
}
Andy Rose
fonte
0

Eu gosto desta maneira:

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

Retirado deste artigo do MSDN .

TrentVB
fonte
0

Espero que isso ajude você.

String fName = "firstname";
String lName = "lastname";
String capitalizedFName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(fName);
String capitalizedLName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(lName);
Uma corrida
fonte
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;

        }
Govind Singh Rawat
fonte
-1

Como edg indicado, você precisará de um algoritmo mais complexo para lidar com nomes especiais (é provavelmente por isso que muitos lugares forçam tudo a maiúsculas).

Algo como este c # não testado deve lidar com o caso simples que você solicitou:

public string SentenceCase(string input)
{
    return input(0, 1).ToUpper + input.Substring(1).ToLower;
}
Michael Haren
fonte
Esqueça isso - usar a classe globalização stackoverflow.com/questions/72831/...
Michael Haren