Jak zapisać wielką literę pierwszej litery imienia i nazwiska w C #?

141

Czy istnieje łatwy sposób na zapisanie pierwszej litery ciągu wielką literą i zmniejszenie pozostałej części? Czy istnieje metoda wbudowana, czy też muszę stworzyć własną?

Mike Roosa
źródło
3
Nie wiem nic o twojej aplikacji, ale myślę, że należy się ogólne ostrzeżenie: programiści nie powinni stosować tej metody do prawdziwych nazw. Myślę, że stary John MacDonald byłby zdenerwowany tą metodą zniekształcania jego imienia, nie wspominając o ee cummings, bell hooks, danah boyd, 松本 行 弘, ludziach z „von” w nazwisku, ludziach o nazwisku „O'Doyle” itp., itd., itd. Większość nazwisk nie jest w formacie „Imię Nazwisko” z tą wielką literą (i znakami z możliwością jej użycia); Polecam lekturę kalzumeus.com/2010/06/17/…
Nick
@Nick ma całkowitą rację. Nie możesz nawet założyć, że mała litera, po której następuje duża litera, jest błędna - irlandzkie imiona robią takie rzeczy jak „Ó hAirt”. Załóżmy, że na jakimkolwiek kongresie, który przychodzi Ci do głowy, pojawi się kultura / język, który Cię zaskoczy.
James Moore

Odpowiedzi:

259

TextInfo.ToTitleCase()zamienia na wielką literę pierwszy znak w każdym tokenie ciągu.
Jeśli nie ma potrzeby zachowywania dużych liter akronimów, należy dołączyć ToLower().

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

Jeśli CurrentCulture jest niedostępna, użyj:

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

Aby uzyskać szczegółowy opis, zobacz łącze MSDN .

ageektrapped
źródło
24
Należy tu zauważyć, że nie działa, jeśli ciąg zawiera tylko wielkie litery. Uważa, że ​​wszystkie kapsle to akronim.
Mike Roosa,
9
W przypadku wielu z nich zauważyłem, że nie można na nich polegać. To nie zadziała, jeśli nazwa będzie przypominać McCain lub jeśli zaczniesz uderzać w bardziej obce nazwy.
Mike Wills,
25
@roosa - łatwe rozwiązanie tego problemu ToTitleCase (val.ToLower ())
Simon_Weaver
+1 Wiedziałem, że to już musi być w FCL, a Google przywiózł mnie tutaj = D
gideon,
13
W przeciwieństwie do poniższej odpowiedzi Nathana, otrzymuję błąd: „Odniesienie do obiektu jest wymagane dla niestatycznego pola, metody lub właściwości…”. Niestety.
Dan W,
117
CultureInfo.CurrentCulture.TextInfo.ToTitleCase("hello world");
Nathan Baulch
źródło
Kurza twarz! Dobra odpowiedź. Zawsze zapominam o sprawach związanych z globalizacją.
Michael Haren,
Świetne rozwiązanie! W sItem = Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(sItem.ToLower) 'first char upper case
VB.Net
Musisz wykryć kulturę każdego imienia , a nie aktualną kulturę. To nie działa w przypadku nazw.
James Moore
1
Skoro to zależy od CurrentCulture, jak możemy być pewni, że nie ma kultury, która traktuje to inaczej?
Rudey
30
String test = "HELLO HOW ARE YOU";
string s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(test);

Powyższy kod nie zadziała .....

więc umieść poniższy kod, konwertując na niższy, a następnie zastosuj funkcję

String test = "HELLO HOW ARE YOU";
string s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(test.ToLower());
Ganesan SubbiahPandian
źródło
15

Istnieją przypadki, które CultureInfo.CurrentCulture.TextInfo.ToTitleCasenie mogą sobie poradzić, na przykład: apostrof '.

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

Regex mogą być również wykorzystywane \b[a-zA-Z]do identyfikacji charakteru wyjściowej słowem po granicy słowa \b, to musimy po prostu zastąpić meczu przez jego górną część obudowy równoważności dzięki Regex.Replace(string input,string pattern,MatchEvaluator evaluator)metodzie:

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

Wyrażenie regularne można w razie potrzeby dostroić, na przykład, jeśli chcemy obsłużyć przypadki MacDonaldi, McFrywyrażenie regularne staje się:(?<=\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

Jeśli musimy obsłużyć więcej prefiksów musimy tylko zmodyfikować grupę (?:mc|mac), na przykład, aby dodać french przedrostki du, de: (?:mc|mac|du|de).

Wreszcie, możemy zdać sobie sprawę, że to wyrażenie regularne będzie również pasowało do przypadku MacDonald'Sostatniego, 'swięc musimy zająć się nim w wyrażeniu regularnym z negatywnym spojrzeniem w tył (?<!'s\b). Na koniec mamy:

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
źródło
@polkduran Staram się znaleźć sposób, aby poradzić sobie z cyframi rzymskimi na końcu imienia; Chciałbym, aby wszystkie były wielkie: John Smith III. Czy negatywne spojrzenie do tyłu mogłoby temu przeszkodzić?
Matt,
Jak to zwykle bywa, w końcu udało mi się odpowiedzieć na własne pytanie. Dodałem opcjonalną grupę, aby dopasować cyfry rzymskie (które będą pisane dużymi literami). Oto pełne wyrażenie regularne, którego teraz używam: (? <= \ B (?: Mc | mac)?) [A-zA-Z] (? <! 'S \ b) (?: ii | iii | iv | v | vi | vii | viii | ix)?
Matt,
Twój przypadek jest specjalny, wyrażenie regularne w odpowiedzi traktuje każde imię (nazwisko) jako izolowane słowo w ciągu wejściowym (testowy ciąg wejściowy ma kilka nazw), więc nie ma w nim pojęcia „koniec nazwy” . Jeśli traktujesz ciąg wejściowy jako pojedynczą nazwę, możesz poprzedzić wyrażenie regularne prostym warunkiem, aby poradzić sobie z przypadkiem: \b[ivxlcdm]+$|tak jest \b[ivxlcdm]+$|(?<=\b(?:mc|mac)?)[a-zA-Z](?<!'s\b). Będzie składać się z wszystkich końcowych słów nazwy mającej nieścisły format liczb rzymskich ( ivxlcdm). Możesz jednak mieć niepożądane wyniki, na przykład „Li” zmieni się w „LI”
polkduran.
Ciekawy. Myślę, że twój dodatek jest prawdopodobnie bardziej poprawny pod względem struktury, ale zgadzam się ... Myślę, że pojawią się pewne kwestie, które powiedziałeś. W powyższym rozwiązaniu zakodowałem na stałe przyrostki do „ix”, co będzie działać w moim przypadku, ale wiem, że może nie być odpowiednie dla wszystkich.
Matt,
1
@ Si8, czy przetestowałeś to? Regex.Replace("JOHN DOE".ToLower(), @"(?<=\b(?:mc|mac)?)[a-zA-Z](?<!'s\b)", m => m.Value.ToUpper())
polkduran
7

Mc i Mac to powszechne przedrostki nazwisk w całych Stanach Zjednoczonych, ale są też inne. TextInfo.ToTitleCase nie obsługuje takich przypadków i nie powinien być używany do tego celu. Oto jak to robię:

    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
źródło
4

Najbardziej bezpośrednią opcją będzie użycie funkcji ToTitleCase, która jest dostępna w .NET, która powinna zajmować się nazwą przez większość czasu. Jak zauważył Edg , jest kilka nazw, dla których to nie zadziała, ale są one dość rzadkie, więc jeśli nie celujesz w kulturę, w której takie nazwy są powszechne, nie jest konieczne coś, o co musisz się zbytnio martwić.

Jeśli jednak nie pracujesz z językiem .NET, to zależy od tego, jak wygląda dane wejściowe - jeśli masz dwa oddzielne pola na imię i nazwisko, możesz po prostu zamienić pierwszą literę na wielką, a resztę za pomocą podciągi.

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

Jeśli jednak otrzymałeś kilka nazwisk jako część tego samego ciągu, musisz wiedzieć, w jaki sposób otrzymujesz informacje i odpowiednio je podzielić . Więc jeśli otrzymujesz imię takie jak „John Doe”, podziel ciąg na podstawie znaku spacji. Jeśli jest w formacie takim jak „Kowalski, Jan”, będziesz musiał podzielić go na podstawie przecinka. Jednak po rozdzieleniu wystarczy zastosować kod pokazany wcześniej.

rjzii
źródło
3

CultureInfo.CurrentCulture.TextInfo.ToTitleCase ("moje imię");

zwraca ~ My Name

Ale problem nadal istnieje w przypadku nazw takich jak McFly, jak wspomniano wcześniej.

David C.
źródło
3
McFry! Konichiwa, Mr. Fugitsu-san
Ian Boyd
@David C Spróbuj zamienić spację na null !! jak string.replace ('', '')
Chintan,
3

Używam własnej metody, aby to naprawić:

Na przykład wyrażenie: „witaj świecie. Witaj, to jest świat przepełnienia stosów”. będzie „Hello World. Hello This Is The Stackoverflow World.”. Regex \ b (początek słowa) \ w (pierwszy znak słowa) załatwi sprawę.

/// <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
źródło
2

Sugestie dotyczące użycia ToTitleCase nie będą działać w przypadku ciągów zawierających wielkie litery. Więc będziesz musiał wywołać ToUpper na pierwszym znaku i ToLower na pozostałych.

Tundey
źródło
6
Dlaczego nie wywołać ToLower w ciągu wejściowym przed wywołaniem ToTitleCase?
Andy Rose,
2

Ta klasa załatwia sprawę. Możesz dodać nowe przedrostki do statycznej tablicy ciągów _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
źródło
1

Jeśli używasz vS2k8, możesz użyć metody rozszerzającej, aby dodać ją do klasy String:

public static string FirstLetterToUpper(this String input)
{
    return input = input.Substring(0, 1).ToUpper() + 
       input.Substring(1, input.Length - 1);
}
FlySwat
źródło
9
Char.ToUpper(input[0]) + input.Substring(1)jest bardziej czytelny IMHO.
Hosam Aly
IMHO input.FirstLetterToUpper()jest z pewnością bardziej czytelne w porównaniu z Char.ToUpper(input[0]) + input.Substring(1), ale mniej przejrzyste
Michael
0

Aby obejść niektóre problemy / problemy, które zostały wyróżnione, sugerowałbym najpierw przekonwertowanie ciągu znaków na małe litery, a następnie wywołanie metody ToTitleCase. Następnie możesz użyć IndexOf („Mc”) lub IndexOf („O \”), aby określić szczególne przypadki, które wymagają bardziej szczegółowej uwagi.

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
źródło
0

Lubię ten sposób:

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

Zaczerpnięte z tego artykułu MSDN .

TrentVB
źródło
0

Mam nadzieję, że to ci pomoże.

String fName = "firstname";
String lName = "lastname";
String capitalizedFName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(fName);
String capitalizedLName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(lName);
Bieg
źródło
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
źródło
-1

Jak wskazał Edg, będziesz potrzebować bardziej złożonego algorytmu do obsługi nazw specjalnych (prawdopodobnie dlatego wiele miejsc wymusza pisanie wielkich liter).

Coś takiego jak ten nieprzetestowany C # powinno obsłużyć prosty przypadek, o który prosiłeś:

public string SentenceCase(string input)
{
    return input(0, 1).ToUpper + input.Substring(1).ToLower;
}
Michael Haren
źródło
Zapomnij o tym - użyj klasy globalizacji stackoverflow.com/questions/72831/…
Michael Haren