Zamień wszystkie pierwsze litery na duże, odpocznij na małe dla każdego słowa


110

Mam ciąg tekstu (głównie około 5-6 słów), który muszę przekonwertować.

Obecnie tekst wygląda następująco:

THIS IS MY TEXT RIGHT NOW

Chcę go przekonwertować na:

This Is My Text Right Now

Mogę przeglądać moją kolekcję ciągów, ale nie jestem pewien, jak wykonać tę modyfikację tekstu.

Odpowiedzi:


251
string s = "THIS IS MY TEXT RIGHT NOW";

s = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(s.ToLower());

31
Haha naprawdę? To gdzie to jest? Uwielbiam .NET, ale niektórzy projektanci API są prawdziwymi palantami.
George Mauer,

7
Zauważ, że chociaż ta metoda zrobi to, o co pytał pytający, jest to naiwny algorytm, który po prostu zamienia każde słowo na wielką literę, bez względu na to, jakiego rodzaju jest to słowo. To nie jest tak naprawdę „wielkość liter”, ponieważ zasady dotyczące wielkości liter w różnych językach są różne. Nie jest to nawet poprawne dla angielskiego. Na przykład tytuł „about a boy” powinien brzmieć „About a boy” w języku angielskim, ale ta metoda daje „About a boy”. Jeśli chcesz prawdziwego tytułu, musisz napisać własną metodę.
Ryan Lundy

18
Nie nazwałbym ich kretynami. Problem z „ToTitleCase” polega na tym, że jest zależny od kultury, dlatego musi znajdować się w przestrzeni nazw System.Globalization. Przechodzenie przez CurrentThread jest po prostu wykonywane w celu uzyskania bieżącej kultury wątku (należy pamiętać, że może to spowodować inne zachowanie, jeśli użytkownik ma inne ustawienia regionalne!). Równie dobrze możesz zrobić „CultureInfo.InvariantCulture.TextInfo.ToTitleCase ()”, co może być lepsze, ponieważ InvariantCulture zachowuje się tak samo we wszystkich kulturach. Poza tym George: Gdzie umieściłbyś funkcję ciągu specyficznego dla kultury?
Michael Stum

3
Zwróć również uwagę na komentarze dotyczące ciągów ALL UPPERCASE: msdn.microsoft.com/en-us/library/…
Michael Stum

2
metoda toLower () powinna być ToLower (), pierwsza litera metody zaczyna się od wielkich liter
Alex

84

Prawdopodobnie wolę wywołać ToTitleCase z CultureInfo ( System.Globalization ) niż Thread.CurrentThread ( System.Threading )

string s = "THIS IS MY TEXT RIGHT NOW";
s = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s.ToLower());

ale powinno być takie samo jak rozwiązanie jspcal

EDYTOWAĆ

W rzeczywistości te rozwiązania nietakie same : CurrentThread--calls -> CultureInfo!


System.Threading.Thread.CurrentThread.CurrentCulture

string s = "THIS IS MY TEXT RIGHT NOW";
s = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(s.ToLower());

IL_0000:  ldstr       "THIS IS MY TEXT RIGHT NOW"
IL_0005:  stloc.0     // s
IL_0006:  call        System.Threading.Thread.get_CurrentThread
IL_000B:  callvirt    System.Threading.Thread.get_CurrentCulture
IL_0010:  callvirt    System.Globalization.CultureInfo.get_TextInfo
IL_0015:  ldloc.0     // s
IL_0016:  callvirt    System.String.ToLower
IL_001B:  callvirt    System.Globalization.TextInfo.ToTitleCase
IL_0020:  stloc.0     // s

System.Globalization.CultureInfo.CurrentCulture

string s = "THIS IS MY TEXT RIGHT NOW";
s = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s.ToLower());

IL_0000:  ldstr       "THIS IS MY TEXT RIGHT NOW"
IL_0005:  stloc.0     // s
IL_0006:  call        System.Globalization.CultureInfo.get_CurrentCulture
IL_000B:  callvirt    System.Globalization.CultureInfo.get_TextInfo
IL_0010:  ldloc.0     // s
IL_0011:  callvirt    System.String.ToLower
IL_0016:  callvirt    System.Globalization.TextInfo.ToTitleCase
IL_001B:  stloc.0     // s

Bibliografia:


16

Istnieje kilka sposobów konwersji pierwszego znaku ciągu na duże litery.

Pierwszym sposobem jest utworzenie metody, która po prostu zamyka pierwszy znak i dołącza resztę ciągu za pomocą podłańcucha:

public string UppercaseFirst(string s)
    {
        return char.ToUpper(s[0]) + s.Substring(1);
    }

Drugim sposobem (który jest nieco szybszy) jest podzielenie ciągu znaków na tablicę znaków, a następnie ponowne zbudowanie ciągu:

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

1
To rozwiązanie nie odpowiada dokładnie na pytanie. Tytuł pytania brzmi: „Zamień wszystkie pierwsze litery na duże, a resztę na małe dla każdego słowa”. Jednak w tym rozwiązaniu wielką literą jest tylko pierwsza litera całego ciągu. Dlatego to rozwiązanie zmieniłoby „hello world” na „Hello world” zamiast „Hello World”.
brsfan

9

Nie przetestowane, ale coś takiego powinno działać:

var phrase = "THIS IS MY TEXT RIGHT NOW";
var rx = new System.Text.RegularExpressions.Regex(@"(?<=\w)\w");
var newString = rx.Replace(phrase,new MatchEvaluator(m=>m.Value.ToLowerInvariant()));

Zasadniczo mówi on „wykonaj dopasowanie wyrażenia regularnego we wszystkich wystąpieniach znaku alfanumerycznego, który następuje po innym znaku alfanumerycznym, a następnie zamień go na własną małą literę”


Dzięki temu wszystkie słowa pisane dużymi literami zaczynają się od wielkich, a kończą małymi. Dokładnie to, czego szukałem.
M. Azyoksul

9

Jeśli używasz na stronie internetowej, możesz również użyć CSS:

style="text-transform:capitalize;"


2
Dlaczego CSS? Gdy pytanie dotyczy wyrażenia regularnego C # asp.net
Jay

1
Znacznik ASP.NETpokazuje, że OP robi to w sieci. Oczywiście nie jest to odpowiedź na pytanie, ponieważ OP wymagał rozwiązania w, C#ale rozwiązuje problem i może być alternatywnym rozwiązaniem. +1
Muhammad Saqib

6

Podczas budowania dużych tabel prędkość jest problemem, więc druga funkcja Jamiego Dixona jest najlepsza, ale nie działa tak, jak jest ...

Nie udaje mu się zamieniać wszystkich liter na małe i zamienia tylko wielką literę na pierwszą literę ciągu, a nie na pierwszą literę każdego słowa w ciągu ... poniższa opcja rozwiązuje oba problemy:

    public string UppercaseFirstEach(string s)
    {
        char[] a = s.ToLower().ToCharArray();

        for (int i = 0; i < a.Count(); i++ )
        {
            a[i] = i == 0 || a[i-1] == ' ' ? char.ToUpper(a[i]) : a[i];

        }

        return new string(a);
    }

Chociaż w tym momencie nie wiadomo, czy jest to nadal najszybsza opcja, Regexrozwiązanie dostarczone przez George'a Mauera może być szybsze ... ktoś, komu zależy na tym, powinien je przetestować.


2
działa, ale zmieniłem to „a.Count ()” na a.Length
Christian

2

Nie wiem, czy poniższe rozwiązanie jest mniej lub bardziej wydajne niż odpowiedź jspcal, ale jestem prawie pewien, że wymaga mniej tworzenia obiektów niż rozwiązanie Jamiego i George'a.

string s = "THIS IS MY TEXT RIGHT NOW";
StringBuilder sb = new StringBuilder(s.Length);
bool capitalize = true;
foreach (char c in s) {
    sb.Append(capitalize ? Char.ToUpper(c) : Char.ToLower(c));
    capitalize = !Char.IsLetter(c);
}
return sb.ToString();

1
Jeśli interesuje nas tworzenie obiektów, dlaczego nie zrobić tego na miejscu z pętlą for indeksującą po s zamiast używać StringBuilder?
jball

0

Oprócz pierwszej odpowiedzi pamiętaj o zmianie indeksu początku wyboru ciągu na koniec słowa, inaczej otrzymasz odwrotną kolejność liter w ciągu.

s.SelectionStart=s.Length;

0

Wypróbuj tę technikę; Zwraca pożądany wynik

CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());

I nie zapomnij użyć System.Globalization.


0

Jedno z możliwych rozwiązań, które może Cię zainteresować. Przechodzenie przez tablicę znaków od prawej do lewej i odwrotnie w jednej pętli.

public static string WordsToCapitalLetter(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentException("value");
        }

        int inputValueCharLength = value.Length;
        var valueAsCharArray = value.ToCharArray();

        int min = 0;
        int max = inputValueCharLength - 1;

        while (max > min)
        {
            char left = value[min];
            char previousLeft = (min == 0) ? left : value[min - 1];

            char right = value[max];
            char nextRight = (max == inputValueCharLength - 1) ? right : value[max - 1];

            if (char.IsLetter(left) && !char.IsUpper(left) && char.IsWhiteSpace(previousLeft))
            {
                valueAsCharArray[min] = char.ToUpper(left);
            }

            if (char.IsLetter(right) && !char.IsUpper(right) && char.IsWhiteSpace(nextRight))
            {
                valueAsCharArray[max] = char.ToUpper(right);
            }

            min++;
            max--;
        }

        return new string(valueAsCharArray);
    }

0

Odpowiedź jspcal jako rozszerzenie ciągu.

Program.cs

class Program
{
    static void Main(string[] args)
    {
        var myText = "MYTEXT";
        Console.WriteLine(myText.ToTitleCase()); //Mytext
    }
}

StringExtensions.cs

using System;
public static class StringExtensions
{

    public static string ToTitleCase(this string str)
    {
        if (str == null)
            return null;

        return System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());
    }
}
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.