Zrób pierwszą literę wielkiej litery (z maksymalną wydajnością)


448

Mam znak „ DetailsViewa” TextBox i chcę, aby dane wejściowe były zapisywane zawsze z PIERWSZYM LITEREM W KAPITALE.

Przykład:

"red" --> "Red"
"red house" --> " Red house"

Jak mogę osiągnąć maksymalizację wydajności ?


UWAGA :
W oparciu o odpowiedzi i komentarze pod odpowiedziami wiele osób uważa, że ​​chodzi tu o wielkie litery wszystkich słów w ciągu. Np => Red House ona nie jest, ale jeśli to jest to, czego szukać , szukać jednej z odpowiedzi, które używa TextInfo„s ToTitleCasemetod. (UWAGA: Odpowiedzi te są niepoprawne dla faktycznie zadanego pytania.)
Zobacz doktrynę TextInfo.ToTitleCase, aby uzyskać zastrzeżenia (nie dotyka słów wielkimi literami - są uważane za akronimy; mogą zawierać małe litery w środku słów, które „nie powinny” być obniżony, np. „McDonald” => „Mcdonald”; nie ma gwarancji, że poradzi sobie z wszystkimi regułami rekapitalizacji dla określonych subtelności).


UWAGA :
Pytanie jest dwuznaczne, czy litery po pierwszej powinny być zmuszone do małych liter . Przyjęta odpowiedź zakłada, że należy zmienić tylko pierwszą literę . Jeśli chcesz wymusić, aby wszystkie litery w łańcuchu oprócz pierwszej były pisane małymi literami, poszukaj odpowiedzi zawierającej ToLower, a nie zawierającej ToTitleCase .


7
@Bobby: To nie jest duplikat: OP prosi o napisanie dużej litery pierwszą literą, pytanie w łączu pisze wielką literą pierwszą literę każdego słowa.
GvS,

1
@GvS: Pierwsza odpowiedź jest bardzo szczegółowa, a pierwszy blok kodu jest dokładnie tym , czego szuka. Ponadto między pisaniem wielkimi literami każdego słowa a tylko pierwszym słowem jest tylko jedna różnica w pętli.
Bobby,

Czy udało Ci się kiedyś rozwiązać ten problem? Czy nadal potrzebujesz w tym pomocy?
jcolebrand

1
Ale powiedziałeś i cytuję: „Zrób pierwszą literę KAŻDEGO SŁOWA wielkimi literami”. Dlaczego więc „czerwony dom” -> „Czerwony dom”? Dlaczego „h” „domu” nie jest wielką literą?
Guillermo Gutiérrez

Dodano odpowiedź, ponieważ większość odpowiedzi nie powiedzie się, jeśli na początku masz białe znaki. aby uniknąć zamieszczania tego przy każdej odpowiedzi, opublikuję go tutaj.
Noctis

Odpowiedzi:


583

Zaktualizowano do C # 8

public static class StringExtensions
{
    public static string FirstCharToUpper(this string input) =>
        input switch
        {
            null => throw new ArgumentNullException(nameof(input)),
            "" => throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input)),
            _ => input.First().ToString().ToUpper() + input.Substring(1)
        };
}

C # 7

public static class StringExtensions
{
    public static string FirstCharToUpper(this string input)
    {
        switch (input)
        {
            case null: throw new ArgumentNullException(nameof(input));
            case "": throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input));
            default: return input.First().ToString().ToUpper() + input.Substring(1);
        }
    }
}

Naprawdę stare odpowiedzi

public static string FirstCharToUpper(string input)
{
    if (String.IsNullOrEmpty(input))
        throw new ArgumentException("ARGH!");
    return input.First().ToString().ToUpper() + String.Join("", input.Skip(1));
}

EDYCJA : Ta wersja jest krótsza. Aby uzyskać szybsze rozwiązanie, spójrz na odpowiedź Equiso

public static string FirstCharToUpper(string input)
{
    if (String.IsNullOrEmpty(input))
        throw new ArgumentException("ARGH!");
    return input.First().ToString().ToUpper() + input.Substring(1);
}

EDYCJA 2 : Prawdopodobnie najszybszym rozwiązaniem jest rozwiązanie Darrena (istnieje nawet test porównawczy), chociaż zmieniłbym jego string.IsNullOrEmpty(s)walidację, aby zgłosić wyjątek, ponieważ pierwotne wymaganie przewiduje istnienie pierwszej litery, aby można ją było pisać dużymi literami. Zauważ, że ten kod działa na ogólny ciąg, a nie szczególnie na prawidłowe wartości z Textbox.


2
Ponieważ pierwszy parametr String.Joinjest separatorem, za pomocą którego można łączyć ciągi podane z drugim parametrem.
Dialecticus

27
Naprawdę podoba mi się twoja odpowiedź, ale var arr = input.ToCharArray(); arr[0] = Char.ToUpperInvariant(arr[0]); return new String(arr);prawdopodobnie zyskałbym trochę prędkości, ponieważ tworzysz mniej niezmienne obiekty (a zwłaszcza pomijasz String.Join). To oczywiście zależy od długości sznurka.
flindeberg

3
Niesamowite - korzystanie z Linq wyjaśnia, co robi ten kod.
Daniel James Bryars

7
Hmmm ... Technicznie rzecz biorąc, powinno to powrócić, "Argh!"aby zachować zasadę wielkiej litery . ;)
kod jp2

2
@ jp2code Ponieważ pisanie wielką nieistniejącą pierwszą literą w pustym lub pustym łańcuchu jest jak uderzenie przez ciężarnego delfina, wtedy ARGH WSZYSTKICH KAPS! to poprawna pisownia. urbandictionary.com/define.php?term=ARGH&defid=67839
Carlos Muñoz

319
public string FirstLetterToUpper(string str)
{
    if (str == null)
        return null;

    if (str.Length > 1)
        return char.ToUpper(str[0]) + str.Substring(1);

    return str.ToUpper();
}

Stara odpowiedź: powoduje to, że każda pierwsza litera jest pisana wielkimi literami

public string ToTitleCase(string str)
{
    return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());
}

Ale to konwertuje każdą pierwszą literę słowa na wielkie litery, a nie tylko pierwszy znak ciągu.
GvS,

@GvS, o to pyta cię pytanie.
thattolleyguy,

17
Pyta „czerwony dom” => „Czerwony dom”. ToTitleCase da ci „Red House”.
GvS,

1
pomocne dla mnie. Świetnie
Ehsan Sajjad

1
Nie jestem tego pewien, ale ciąg char + powoduje boks. Na wszelki wypadek wymagana jest maksymalna wydajność.
nawfal

164

Właściwy sposób to użycie Kultury:

System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(word.ToLower())

Uwaga: Spowoduje to wielkie litery każdego słowa w ciągu, np. „Czerwony dom” -> „czerwony dom”. Rozwiązanie to będzie także używać wielkich liter w słowach, np. „Stary McDonald” -> „stary Mcdonald”.


4
Jest to najbardziej odpowiedni sposób, aby to zrobić, zamiast odkrywać koło i spróbować napisać własną wersję tego.
Alexey Shevelyov

12
Mam z tym problem, że czyści potencjalnie ważne duże litery, które są w połowie łańcucha. np. McNames
Jecoms 24.09.16

29
To nieprawidłowa odpowiedź, ponieważ „czerwony dom” staje się „czerwonym domem” (zwróć uwagę na „H”)!
spaark

21
Sześć lat po zadaniu pytania proszę o dokładniejsze przeczytanie istniejących odpowiedzi i ich komentarzy . Jeśli jesteś przekonany, że masz lepsze rozwiązanie, to pokaż sytuacje, w których Twoja odpowiedź zachowuje się w sposób, który Twoim zdaniem jest lepszy, a konkretnie, w jaki sposób różni się ona od istniejących odpowiedzi. 1) Equiso omówił już tę opcję w drugiej połowie swojej odpowiedzi. 2) W wielu sytuacjach ToLowerjest błędem, ponieważ usuwa duże litery w środku słowa, np. „McDonalds”. 3) Pytanie dotyczy zmiany tylko pierwszego słowa ciągu , a nie tytułu.
ToolmakerSteve

10
To zamienia dane wejściowe w „Tytuł Case” - więc zmienia „czerwonego konia” w „Czerwonego konia” - podczas gdy osoba pytająca wyraźnie stwierdziła, że ​​NIE powinna tego robić (i zwraca „Czerwony koń”). To nie jest właściwa droga.
Hekkaryk

68

Wybrałem najszybszą metodę z http://www.dotnetperls.com/uppercase-first-letter i przekonwertowałem na metodę rozszerzenia:

    /// <summary>
    /// Returns the input string with the first character converted to uppercase, or mutates any nulls passed into string.Empty
    /// </summary>
    public static string FirstLetterToUpperCaseOrConvertNullToEmptyString(this string s)
    {
        if (string.IsNullOrEmpty(s))
            return string.Empty;

        char[] a = s.ToCharArray();
        a[0] = char.ToUpper(a[0]);
        return new string(a);
    }

UWAGA: Powodem użycia ToCharArrayjest szybszy niż alternatywa char.ToUpper(s[0]) + s.Substring(1), ponieważ przydzielany jest tylko jeden ciąg, podczas gdy Substringpodejście przydziela ciąg dla podłańcucha, a następnie drugi ciąg, aby skomponować wynik końcowy.


EDYCJA : Oto jak to podejście wygląda w połączeniu ze wstępnym testem zaakceptowanym przez CarlosMuñoz :

    /// <summary>
    /// Returns the input string with the first character converted to uppercase
    /// </summary>
    public static string FirstLetterToUpperCase(this string s)
    {
        if (string.IsNullOrEmpty(s))
            throw new ArgumentException("There is no first letter");

        char[] a = s.ToCharArray();
        a[0] = char.ToUpper(a[0]);
        return new string(a);
    }

Wow, dziękuję za znalezienie wskaźników wydajności, aby pokazać rozwiązanie o najwyższej wydajności!
ToolmakerSteve

@ToolmakerSteve, podoba mi się to rozwiązanie, ponieważ rzeczywiście wydaje się szybsze niż inne, ale jest z tym mały problem. Jeśli podasz null, nie powinieneś otrzymać pustego ciągu jako wyniku. W rzeczywistości argumentowałbym, że nawet przekazanie pustego ciągu powinno wygenerować wyjątek, ponieważ OP prosi o pierwszą literę. Możesz także skomentować odpowiedź innych osób przed ich edycją.
Carlos Muñoz,

@ CarlosMuñoz - w meta dyskutowano, czy „poprawić” odpowiedzi innych osób. Konsensus brzmiał: „jeśli możesz poprawić odpowiedź, to zrób to - nikt nie jest właścicielem odpowiedzi, nawet autor oryginalny - celem jest uzyskanie najlepszych możliwych odpowiedzi”. Oczywiście możesz swobodnie edytować lub cofać edycję. W takim przypadku powszechna uprzejmość pozwoliłaby, aby oryginalna wersja autora była ostatecznym rezultatem, i zadowoliłbym się komentarzem. Zwykle również umieścić w komentarzu się zmianę czynię; Przepraszam, jeśli nie.
ToolmakerSteve

@ CarlosMuñoz - w szczególności w SO jest wiele, wiele odpowiedzi, które nie są aktywnie utrzymywane. Jeśli zmiana poprawi odpowiedź, to po co zostawiać ją w komentarzu? Jeśli autor aktywnie monitoruje swoje odpowiedzi, zrobi to ze zmianami według własnego uznania. Jeśli nie są, odpowiedź została poprawiona, z korzyścią dla wszystkich. Ta zasada jest szczególnie prawdziwa w przypadku starych pytań i odpowiedzi, takich jak ta.
ToolmakerSteve

BTW, zgadzam się z @ CarlosMuñoz na temat testu na początku metody - jego wersja tego testu ma lepszy styl programowania - return string.Emptytutaj ukryłoby się „złe” wywołanie metody.
ToolmakerSteve

46

Możesz użyć „metody ToTitleCase”

string s = new CultureInfo("en-US").TextInfo.ToTitleCase("red house");
//result : Red House

ta metoda rozszerzenia rozwiązuje każdy problem z tytułem.

łatwy w użyciu

string str = "red house";
str.ToTitleCase();
//result : Red house

string str = "red house";
str.ToTitleCase(TitleCase.All);
//result : Red House

metoda rozszerzenia

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

namespace Test
{
    public static class StringHelper
    {
        private static CultureInfo ci = new CultureInfo("en-US");
        //Convert all first latter
        public static string ToTitleCase(this string str)
        {
            str = str.ToLower();
            var strArray = str.Split(' ');
            if (strArray.Length > 1)
            {
                strArray[0] = ci.TextInfo.ToTitleCase(strArray[0]);
                return string.Join(" ", strArray);
            }
            return ci.TextInfo.ToTitleCase(str);
        }
        public static string ToTitleCase(this string str, TitleCase tcase)
        {
            str = str.ToLower();
            switch (tcase)
            {
                case TitleCase.First:
                    var strArray = str.Split(' ');
                    if (strArray.Length > 1)
                    {
                        strArray[0] = ci.TextInfo.ToTitleCase(strArray[0]);
                        return string.Join(" ", strArray);
                    }
                    break;
                case TitleCase.All:
                    return ci.TextInfo.ToTitleCase(str);
                default:
                    break;
            }
            return ci.TextInfo.ToTitleCase(str);
        }
    }

    public enum TitleCase
    {
        First,
        All
    }
}

Problem w rozwiązaniu polega na tym, że „czerwony dom” zostanie przekształcony w „czerwony dom”, a nie w „czerwony dom”, zgodnie z pytaniem.
Vadim,

3
@Tacttin Działa, ale poniższy kod jest łatwiejszy do odczytania i działa lepiej char.ToUpper (tekst [0]) + ((text.Length> 1)? Text.Substring (1) .ToLower (): string.Empty) ; Możesz przeczytać więcej @ vkreynin.wordpress.com/2013/10/09/…
Vadim,

1
Nie podoba mi się to rozwiązanie, ponieważ łączy dwie zupełnie różne sytuacje w jedną długą metodę. Nie widzę też korzyści pojęciowej. A wdrożenie kapitalizacji tylko pierwszej litery jest ... śmieszne. Jeśli chcesz użyć dużej litery do pierwszej litery, oczywistą implementacją jest po prostu wielkie litery (ToUpper) . Zamiast tego miałbym dwie osobne metody. FirstLetterToUpperw odpowiedzi Equiso (lub w nowszej odpowiedzi Guillerneta) i ToTitleCasetutaj, ale bez drugiego parametru. Więc nie potrzebujesz enum TitleCase.
ToolmakerSteve

31

Dla pierwszej litery ze sprawdzaniem błędów:

public string CapitalizeFirstLetter(string s)
{
    if (String.IsNullOrEmpty(s))
        return s;
    if (s.Length == 1)
        return s.ToUpper();
    return s.Remove(1).ToUpper() + s.Substring(1);
}

A oto to samo, co przydatne rozszerzenie

public static string CapitalizeFirstLetter(this string s)
    {
    if (String.IsNullOrEmpty(s)) return s;
    if (s.Length == 1) return s.ToUpper();
    return s.Remove(1).ToUpper() + s.Substring(1);
    }

Czyste podejście. Dziękuję Ci!
Philippe,

11
public static string ToInvarianTitleCase(this string self)
{
    if (string.IsNullOrWhiteSpace(self))
    {
        return self;
    }

    return CultureInfo.InvariantCulture.TextInfo.ToTitleCase(self);
}

6

Jeśli problemem jest użycie wydajności / pamięci, ten tworzy tylko jeden (1) StringBuilder i jeden (1) nowy Ciąg o tym samym rozmiarze co Ciąg Oryginalny.

public static string ToUpperFirst(this string str) {
  if( !string.IsNullOrEmpty( str ) ) {
    StringBuilder sb = new StringBuilder(str);
    sb[0] = char.ToUpper(sb[0]);

    return sb.ToString();

  } else return str;
}

3
Można to zrobić za pomocą prostej, char[]a nie całej infrastruktury StringBuilder. Zamiast new StringBuilder(str), użyj str.ToCharArray()i zamiast sb.ToString(), użyj new string(charArray). StringBuilderemuluje rodzaj indeksowania, który tablica znaków odsłania natywnie, więc rzeczywista .ToUpperlinia może być zasadniczo taka sama. :-)
Jonathan Gilbert

Darren (rok później) pokazuje, jak to zrobić ToCharArray, zgodnie z sugestią @JonathanGilbert
ToolmakerSteve

6

Najszybsza metoda.

  private string Capitalize(string s){
        if (string.IsNullOrEmpty(s))
        {
            return string.Empty;
        }
        char[] a = s.ToCharArray();
        a[0] = char.ToUpper(a[0]);
        return new string(a);
}

Testy pokazują kolejne wyniki (ciąg znaków z wejściowymi symbolami 10000000): Wyniki testu


1
Polecam zwracanie sparametru, gdy jest pusty lub pusty.
MatrixRonny,

4

Spróbuj tego:

static public string UpperCaseFirstCharacter(this string text) {
    return Regex.Replace(text, "^[a-z]", m => m.Value.ToUpper());
}

2
lub może jakąś inną klasę znaków (np. alfanumeryczną \ w), dzięki czemu funkcja
rozpoznaje

@ DmitryLedentsov- C # klasa ciągów jest zbudowana na znakach UTF-16. String Class „Reprezentuje tekst jako sekwencję jednostek kodu UTF-16.”
ToolmakerSteve

4

Jeśli zależy Ci tylko na pisaniu wielkiej litery i nie ma znaczenia reszta ciągu, możesz po prostu wybrać pierwszy znak, ustawić wielkie litery i połączyć go z resztą ciągu bez oryginalnego pierwszego znaku.

String word ="red house";
word = word[0].ToString().ToUpper() + word.Substring(1, word.length -1);
//result: word = "Red house"

Musimy przekonwertować pierwszy znak na ToString (), ponieważ odczytujemy go jako tablicę Char, a typ Char nie ma metody ToUpper ().


3

Oto sposób, aby to zrobić jako metodę rozszerzenia:

static public string UpperCaseFirstCharacter(this string text)
{
    if (!string.IsNullOrEmpty(text))
    {
        return string.Format(
            "{0}{1}",
            text.Substring(0, 1).ToUpper(),
            text.Substring(1));
    }

    return text;
}

Można wtedy nazwać:

//yields "This is Brian's test.":
"this is Brian's test.".UpperCaseFirstCharacter(); 

A oto kilka testów jednostkowych:

[Test]
public void UpperCaseFirstCharacter_ZeroLength_ReturnsOriginal()
{
    string orig = "";
    string result = orig.UpperCaseFirstCharacter();

    Assert.AreEqual(orig, result);
}

[Test]
public void UpperCaseFirstCharacter_SingleCharacter_ReturnsCapital()
{
    string orig = "c";
    string result = orig.UpperCaseFirstCharacter();

    Assert.AreEqual("C", result);
}

[Test]
public void UpperCaseFirstCharacter_StandardInput_CapitalizeOnlyFirstLetter()
{
    string orig = "this is Brian's test.";
    string result = orig.UpperCaseFirstCharacter();

    Assert.AreEqual("This is Brian's test.", result);
}

1
string.Formatto przesada; po prostu zrób text.Substring(0, 1).ToUpper() + text.Substring(1).
ToolmakerSteve

3

Ponieważ akurat nad tym pracowałem i szukałem pomysłów, oto rozwiązanie, do którego doszedłem. Używa LINQ i będzie w stanie zapisać wielką literę ciągu, nawet jeśli pierwsze wystąpienie nie jest literą. Oto metoda rozszerzenia, którą ostatecznie opracowałem.

public static string CaptalizeFirstLetter(this string data)
{
    var chars = data.ToCharArray();

    // Find the Index of the first letter
    var charac = data.First(char.IsLetter);
    var i = data.IndexOf(charac);

    // capitalize that letter
    chars[i] = char.ToUpper(chars[i]);

    return new string(chars);
}

Jestem pewien, że istnieje sposób, aby to trochę zoptymalizować lub oczyścić.



3

Sprawdź, czy łańcuch nie jest pusty, a następnie przekonwertuj pierwszy znak na wielkie litery, a resztę na małe:

public static string FirstCharToUpper(string str)
{
    return str?.First().ToString().ToUpper() + str?.Substring(1).ToLower();
}

Dziękujemy za małe rozwiązanie zamiast kilku wierszy kodu tylko za słowo łańcuchowe!
Imran Faruqi

2

To zrobi, chociaż upewni się również, że nie ma błędnych liter, które nie byłyby na początku słowa.

public string(string s)
{
System.Globalization.CultureInfo c = new System.Globalization.CultureInfo("en-us", false)
System.Globalization.TextInfo t = c.TextInfo;

return t.ToTitleCase(s);
}

2
Wymaga zerowego sprawdzenia sprzed wywołaniem ToTitleCase.
Taras Alenin

@ CarlosMuñoz tlhIngan Hol nie ma w swoim skrypcie obudowy na litery. :-)
Jonathan Gilbert

2

Wydaje się, że jest tutaj dużo złożoności, gdy wszystko, czego potrzebujesz, to:

    /// <summary>
    /// Returns the input string with the first character converted to uppercase if a letter
    /// </summary>
    /// <remarks>Null input returns null</remarks>
    public static string FirstLetterToUpperCase(this string s)
    {
        if (string.IsNullOrWhiteSpace(s))
            return s;

        return char.ToUpper(s[0]) + s.Substring(1);
    }

Godne uwagi punkty:

  1. Jest to metoda rozszerzenia.

  2. Jeśli dane wejściowe są puste, puste lub spacja, dane wejściowe są zwracane w niezmienionej postaci.

  3. String.IsNullOrWhiteSpace został wprowadzony w .NET Framework 4. To nie będzie działać ze starszymi frameworkami.


1
Nie rozumiem, jak to jest poprawa w stosunku do pierwotnie przyjętej odpowiedzi sprzed czterech lat. W rzeczywistości jest to niespójne (nieszkodliwie tak, ale cztery lata późno, mam wysokie standardy dla nowej odpowiedzi dodając korzyść): Jedyną zaletą korzystania z nowszych IsNullOrWhiteSpacezamiast IsNullOrEmpty, to jeśli masz zamiar znaleźć i zmienić pierwszy nieprzestrzegania biała przestrzeń . Ale ty nie - zawsze działasz s[0]. Jest więc bezużyteczny [zarówno semantycznie, jak i wydajności] w użyciu IsNullOrWhiteSpace.
ToolmakerSteve

... dlaczego takie użycie IsNullOrWhiteSpacemnie niepokoi, że niedbały czytelnik może pomyśleć: „Sprawdził, czy nie ma białych znaków, więc poniższy kod naprawdę znajduje i zmienia literę, nawet jeśli poprzedza ją biała spacja”. Ponieważ kod nie zmieni pierwszej „litery” poprzedzonej spacją, użycie IsNullOrWhiteSpacemoże wprowadzić w błąd tylko czytelnika.
ToolmakerSteve

... Ups, nie mam na myśli przyjętej odpowiedzi, mam na myśli odpowiedź Equiso z tego samego okresu.
ToolmakerSteve

1
string emp="TENDULKAR";
string output;
output=emp.First().ToString().ToUpper() + String.Join("", emp.Skip(1)).ToLower();

Dlaczego ToLower () na ogonie ?. Nie ma wymagań dla innych liter, ale pierwsza.
Carlos Muñoz

Stringmoże być czymkolwiek Upperlub. więc Lowerjest to ogólne rozwiązanie dla całego łańcucha.
Shailesh

Dlaczego Joinzamiast emp.First().ToString().ToUpper() + emp.Substring(1);? Prawdopodobnie trzeba być bardziej defensywny też: output = string.IsNullOrEmpty(emp) ? string.Empty : [...]. Ponadto, fwiw, zgódź się z @ CarlosMuñoz - nie potrzebujesz odpowiedzi ToLower()na pytanie PO.
ruffin

@ ruffin -> using Substring to również dobry styl pisania kodu, zgadzam się na twoje rozwiązanie przycinania kodu, ale w tym przypadku pisanie ToLower()jest dobrą praktyką programistyczną. stringmoże być cokolwiek W Upperprzypadku, gdy Lowersprawa zależy od danych wejściowych użytkownika, podaję ogólne rozwiązanie.
Shailesh,

@Shailesh - Jednak pytanie, czy nie zażądać tylko pierwsza litera być kapitał. Poprosił o zmianę pierwszej litery na wielką. Bez dalszych wyjaśnień autora, najbardziej naturalnym założeniem jest to, że pozostała część łańcucha nie ulegnie zmianie. Biorąc pod uwagę, że odpowiadasz trzy lata później , załóż, że zaakceptowana odpowiedź odpowiada żądaniom pytającego. Podaj inną odpowiedź tylko wtedy, gdy istnieje jakiś techniczny powód, aby zrobić to inaczej.
ToolmakerSteve

1

Chciałem udzielić odpowiedzi „MAKSYMALNA WYDAJNOŚĆ”. Moim zdaniem odpowiedź „MAKSYMALNA WYDAJNOŚĆ” obejmuje wszystkie scenariusze i zapewnia odpowiedź na pytanie uwzględniające te scenariusze. Oto moja odpowiedź. Z tych powodów:

  1. IsNullOrWhiteSpace uwzględnia ciągi znaków, które są tylko spacjami lub pustymi / pustymi.
  2. .Trim () usuwa białe znaki z przodu i tyłu łańcucha.
  3. .First () przyjmuje pierwszy znak niezliczonej liczby (lub łańcucha).
  4. Powinniśmy sprawdzić, czy jest to litera, która może / powinna być pisana wielkimi literami.
  5. Następnie dodajemy resztę ciągu, tylko jeśli długość wskazuje, że powinniśmy.
  6. Zgodnie z najlepszą praktyką .Net powinniśmy zapewnić kulturę w System.Globalization.CultureInfo.
  7. Podanie ich jako parametrów opcjonalnych sprawia, że ​​ta metoda jest w pełni wielokrotnego użytku, bez konieczności wpisywania wybranej kultury za każdym razem.

    public static string capString(string instring, string culture = "en-US", bool useSystem = false)
    {
        string outstring;
        if (String.IsNullOrWhiteSpace(instring))
        {
            return "";
        }
        instring = instring.Trim();
        char thisletter = instring.First();
        if (!char.IsLetter(thisletter))
        {
            return instring;   
        }
        outstring = thisletter.ToString().ToUpper(new CultureInfo(culture, useSystem));
        if (instring.Length > 1)
        {
            outstring += instring.Substring(1);
        }
        return outstring;
    }

2
Chociaż dotyczy to większości przypadków, czy nie byłoby to raczej powolne, biorąc pod uwagę liczbę ciągów tworzonych przy każdej operacji? Tutaj odbywa się mnóstwo alokacji ciągów. Najlepiej byłoby, gdyby został przydzielony tylko raz i tylko raz.
Douglas Gaskell,

1

Ostatnio miałem podobne wymaganie i pamiętałem, że funkcja LINQ Select () zapewnia indeks:

string input;
string output;

input = "red house";
output = String.Concat(input.Select((currentChar, index) => index == 0 ? Char.ToUpper(currentChar) : currentChar));
//output = "Red house"

Ponieważ potrzebuję tego bardzo często, stworzyłem metodę rozszerzenia dla typu ciągu:

public static class StringExtensions
{
    public static string FirstLetterToUpper(this string input)
    {
        if (string.IsNullOrEmpty(input))
            return string.Empty;
        return String.Concat(input.Select((currentChar, index) => index == 0 ? Char.ToUpper(currentChar) : currentChar));
    }
}

Pamiętaj, że tylko pierwsza litera jest konwertowana na wielkie litery - wszystkie pozostałe znaki nie są dotykane. Jeśli potrzebujesz, aby pozostałe znaki były pisane małymi literami, możesz także wywołać Char.ToLower (currentChar) dla indeksu> 0 lub wywołać ToLower () na całym ciągu.

Jeśli chodzi o wydajność, porównałem kod z rozwiązaniem Darrena. Na mojej maszynie kod Darrena jest około 2 razy szybszy, co nie jest zaskoczeniem, ponieważ bezpośrednio edytuje tylko pierwszą literę w tablicy znaków. Proponuję więc wziąć kod Darrena, jeśli potrzebujesz najszybszego dostępnego rozwiązania. Jeśli chcesz zintegrować również inne manipulacje ciągami znaków, może być wygodne, aby ekspresyjna moc funkcji lambda dotykała znaków ciągu wejściowego - możesz łatwo rozszerzyć tę funkcję - więc zostawiam to rozwiązanie tutaj.


Zastanawiałem się, jak rozwiązać ten problem, opracowałem własne rozwiązanie, a potem wróciłem, aby opublikować je tylko po to, by znaleźć dokładnie to samo rozwiązanie, które już miałem. +1 dla Ciebie!
BlueFuzzyThing

Dziękuję Ci bardzo.
Grimm

1

Myślę, że poniższa metoda jest najlepszym rozwiązaniem

    class Program
{
    static string UppercaseWords(string value)
    {
        char[] array = value.ToCharArray();
        // Handle the first letter in the string.
        if (array.Length >= 1)
        {
            if (char.IsLower(array[0]))
            {
                array[0] = char.ToUpper(array[0]);
            }
        }
        // Scan through the letters, checking for spaces.
        // ... Uppercase the lowercase letters following spaces.
        for (int i = 1; i < array.Length; i++)
        {
            if (array[i - 1] == ' ')
            {
                if (char.IsLower(array[i]))
                {
                    array[i] = char.ToUpper(array[i]);
                }
            }
        }
        return new string(array);
    }

    static void Main()
    {
        // Uppercase words in these strings.
        const string value1 = "something in the way";
        const string value2 = "dot net PERLS";
        const string value3 = "String_two;three";
        const string value4 = " sam";
        // ... Compute the uppercase strings.
        Console.WriteLine(UppercaseWords(value1));
        Console.WriteLine(UppercaseWords(value2));
        Console.WriteLine(UppercaseWords(value3));
        Console.WriteLine(UppercaseWords(value4));
    }
}

Output

Something In The Way
Dot Net PERLS
String_two;three
 Sam

ref


1

Ponieważ pytanie dotyczy maksymalizacji wydajności , zaadaptowałem wersję Darrena do Spans, która redukuje śmieci i poprawia prędkość o około 10%.

        /// <summary>
        /// Returns the input string with the first character converted to uppercase
        /// </summary>
        public static string ToUpperFirst(this string s)
        {
            if (string.IsNullOrEmpty(s))
                throw new ArgumentException("There is no first letter");

            Span<char> a = stackalloc char[s.Length];
            s.AsSpan(1).CopyTo(a.Slice(1));
            a[0] = char.ToUpper(s[0]);
            return new string(a);
        }

Wydajność

|  Method |      Data |      Mean |     Error |    StdDev |
|-------- |---------- |----------:|----------:|----------:|
|  Carlos |       red | 107.29 ns | 2.2401 ns | 3.9234 ns |
|  Darren |       red |  30.93 ns | 0.9228 ns | 0.8632 ns |
| Marcell |       red |  26.99 ns | 0.3902 ns | 0.3459 ns |
|  Carlos | red house | 106.78 ns | 1.9713 ns | 1.8439 ns |
|  Darren | red house |  32.49 ns | 0.4253 ns | 0.3978 ns |
| Marcell | red house |  27.37 ns | 0.3888 ns | 0.3637 ns |

Pełny kod testowy

using System;
using System.Linq;

using BenchmarkDotNet.Attributes;

namespace CorePerformanceTest
{
    public class StringUpperTest
    {
        [Params("red", "red house")]
        public string Data;

        [Benchmark]
        public string Carlos() => Data.Carlos();

        [Benchmark]
        public string Darren() => Data.Darren();

        [Benchmark]
        public string Marcell() => Data.Marcell();
    }

    internal static class StringExtensions
    {
        public static string Carlos(this string input) =>
            input switch
            {
                null => throw new ArgumentNullException(nameof(input)),
                "" => throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input)),
                _ => input.First().ToString().ToUpper() + input.Substring(1)
            };

        public static string Darren(this string s)
        {
            if (string.IsNullOrEmpty(s))
                throw new ArgumentException("There is no first letter");

            char[] a = s.ToCharArray();
            a[0] = char.ToUpper(a[0]);
            return new string(a);
        }

        public static string Marcell(this string s)
        {
            if (string.IsNullOrEmpty(s))
                throw new ArgumentException("There is no first letter");

            Span<char> a = stackalloc char[s.Length];
            s.AsSpan(1).CopyTo(a.Slice(1));
            a[0] = char.ToUpper(s[0]);
            return new string(a);
        }
    }

}

Edycja: Wystąpiła literówka, zamiast s [0], było [0] - to skutkuje spłaszczeniem tej samej, pustej wartości do przydzielonego zakresu a.


0

W ten sposób pierwsza litera i każda litera następująca po spacji i małe litery są pisane wielką literą.

public string CapitalizeFirstLetterAfterSpace(string input)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder(input);
    bool capitalizeNextLetter = true;
    for(int pos = 0; pos < sb.Length; pos++)
    {
        if(capitalizeNextLetter)
        {
            sb[pos]=System.Char.ToUpper(sb[pos]);
            capitalizeNextLetter = false;
        }
        else
        {
            sb[pos]=System.Char.ToLower(sb[pos]);
        }

        if(sb[pos]=' ')
        {
            capitalizeNextLetter=true;
        }
    }
}

1
Lub jeśli nie chcesz pisać ścian kodu - CultureInfo.CurrentCulture.TextInfo.ToTitleCase (theString); robi to samo.
Chev

Tak ... nie wiedziałem o tym :) I z powodu mojej ogromnej ilości kodu odpowiedzi wszystkich innych pojawiły się podczas pisania.
thattolleyguy,

AKTUALIZACJA: 1) Niewielka różnica między tą odpowiedzią a ToTitleCase polega na tym, że ta odpowiedź zmusza słowa, które są wielkimi literami, do przekształcenia się w TitleCase, podczas gdy ToTitleCase pozostawia takie słowa w spokoju (zakłada, że ​​mogą to być akronimy). To może być lub nie być pożądane. Zaletą takiego kodu jest to, że można go dowolnie modyfikować. 2) nie będzie to poprawnie obsługiwać białych znaków innych niż „”. powinien zastąpić test zerowy testem spacji.
ToolmakerSteve

0

Użyj następującego kodu:

string  strtest ="PRASHANT";
strtest.First().ToString().ToUpper() + strtest.Remove(0, 1).ToLower();

Mojemu przedstawicielowi nie warto nawet głosować za odpowiedzią dodaną po latach, co jest oczywiście równoważne z już istniejącymi odpowiedziami. Jeśli zamierzasz dodać nową odpowiedź do pytania zawierającego wiele odpowiedzi, wyjaśnij, co Twoim zdaniem jest lepsze w stosunku do Twojej odpowiedzi, lub w jakich okolicznościach Twoja odpowiedź byłaby bardziej przydatna niż inne odpowiedzi. Być specyficznym.
ToolmakerSteve

0

Wygląda na to, że żadne z podanych tutaj rozwiązań nie zajmie się białą spacją przed ciągiem.

Dodając to jako myśl:

public static string SetFirstCharUpper2(string aValue, bool aIgonreLeadingSpaces = true)
{
    if (string.IsNullOrWhiteSpace(aValue))
        return aValue;

    string trimmed = aIgonreLeadingSpaces 
           ? aValue.TrimStart() 
           : aValue;

    return char.ToUpper(trimmed[0]) + trimmed.Substring(1);
}   

Powinien obsłużyć this won't work on other answers(to zdanie ma spację na początku), a jeśli nie podoba ci się przycinanie spacji, po prostu przekaż falsejako drugi parametr (lub zmień wartość domyślną na falsei podaj, truejeśli chcesz zajmować się spacją)



0

Najłatwiejszym sposobem na pisanie wielkich liter jest:

1- Korzystanie z Sytem.Globalization;

  // Creates a TextInfo based on the "en-US" culture.
  TextInfo myTI = new CultureInfo("en-US",false).

  myTI.ToTitleCase(textboxname.Text)

`


1
Ta odpowiedź jest zasadniczo identyczna z odpowiedziami udzielonymi wiele lat wcześniej. Nic nie dodaje do dyskusji.
ToolmakerSteve

Jest to również błędne, podobnie jak komentarz w drugim, zamienia każdą pierwszą literę wszystkimi słowami na wielką, a nie na czerwoną, zamiast na czerwony.
DeadlyChambers

0

następująca funkcja jest poprawna na wszystkie sposoby:

static string UppercaseWords(string value)
{
    char[] array = value.ToCharArray();
    // Handle the first letter in the string.
    if (array.Length >= 1)
    {
        if (char.IsLower(array[0]))
        {
            array[0] = char.ToUpper(array[0]);
        }
    }
    // Scan through the letters, checking for spaces.
    // ... Uppercase the lowercase letters following spaces.
    for (int i = 1; i < array.Length; i++)
    {
        if (array[i - 1] == ' ')
        {
            if (char.IsLower(array[i]))
            {
                array[i] = char.ToUpper(array[i]);
            }
        }
    }
    return new string(array);
}

Znalazłem to tutaj


Dlaczego? Po co dodawać kolejną odpowiedź, skoro jest już tak wiele odpowiedzi, które wydają się podobne? Co jest nie tak z wszystkimi istniejącymi odpowiedziami, które skłoniły cię do dodania kolejnej?
ToolmakerSteve

Ponieważ to answare jest poprawne na wszystkie sposoby. Spokojnie.

Przepraszam; Byłem niepotrzebnie surowy. Pozostanę przy faktach: 1) Zasadniczo jest to ta sama odpowiedź, co siedem lat wcześniej. 2) Ma to tę samą wadę, co odpowiedź: nie obsługuje białych znaków innych niż puste znaki. 3) To odpowiedź na nieco inne pytanie niż OP. Użyj takiej odpowiedzi, jeśli chcesz, by wszystkie słowa były pisane wielką literą. 4) Zwykle najprostszym sposobem osiągnięcia tego jest użycie TitleInfo.ToTitleCase. (Z drugiej strony zaletą przykładowego kodu można dostosować według potrzeb.)
ToolmakerSteve

Korygując się: To coś innego niż podejście Tolleyguya: pozostawia nietknięte litery, które nie są pierwszą literą słowa. Zamiast tego jest duplikatem odpowiedzi Zamoldaru . Przychylnie, uznanie dla Darian dla podając link do źródła - wydaje zamoldar plagiat bez udzielenia kredytu. Z powodu udostępnienia linku źródłowego, a tym samym usprawnienia dyskusji , popieram tę odpowiedź, pomimo mojej krytyki.
ToolmakerSteve

1
Darian, można wprowadzić dwie ulepszenia: 1) użyj char.IsWhiteSpace( array[ i -1 ] )zamiast .. == ' ', aby obsłużyć całą białą przestrzeń. 2) usuń dwa miejsca, które to robią if (char.isLower(..))- nie służą one celowi. ToUpperpo prostu nic nie robi, jeśli postać nie ma małych liter.
ToolmakerSteve

0

Rozwijając powyższe pytanie Carlosa, jeśli chcesz użyć wielu zdań, możesz użyć tego kodu:

    /// <summary>
    /// Capitalize first letter of every sentence. 
    /// </summary>
    /// <param name="inputSting"></param>
    /// <returns></returns>
    public string CapitalizeSentences (string inputSting)
    {
        string result = string.Empty;
        if (!string.IsNullOrEmpty(inputSting))
        {
            string[] sentences = inputSting.Split('.');

            foreach (string sentence in sentences)
            {
                result += string.Format ("{0}{1}.", sentence.First().ToString().ToUpper(), sentence.Substring(1)); 
            }
        }

        return result; 
    }

0

Możliwe rozwiązanie problemu.

   public static string FirstToUpper(this string lowerWord)
   {
       if (string.IsNullOrWhiteSpace(lowerWord) || string.IsNullOrEmpty(lowerWord))
            return lowerWord;
       return new StringBuilder(lowerWord.Substring(0, 1).ToUpper())
                 .Append(lowerWord.Substring(1))
                 .ToString();
   }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.