Jaka jest różnica między ToUpper () a ToUpperInvariant () w języku C #?

135

W języku C # jaka jest różnica między ToUpper()i ToUpperInvariant()?

Czy możesz podać przykład, w którym wyniki mogą być inne?

Lill Lansey
źródło
3
[Organizacja] Czy to pytanie powinno mieć tag „internacjonalizacja”?
jasso

Odpowiedzi:

156

ToUpperużywa aktualnej kultury. ToUpperInvariantużywa niezmiennej kultury.

Kanonicznym przykładem jest Turcja, gdzie duże litery „i” nie są „I”.

Przykładowy kod pokazujący różnicę:

using System;
using System.Drawing;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;

public class Test
{
    [STAThread]
    static void Main()
    {
        string invariant = "iii".ToUpperInvariant();
        CultureInfo turkey = new CultureInfo("tr-TR");
        Thread.CurrentThread.CurrentCulture = turkey;
        string cultured = "iii".ToUpper();

        Font bigFont = new Font("Arial", 40);
        Form f = new Form {
            Controls = {
                new Label { Text = invariant, Location = new Point(20, 20),
                            Font = bigFont, AutoSize = true},
                new Label { Text = cultured, Location = new Point(20, 100),
                            Font = bigFont, AutoSize = true }
            }
        };        
        Application.Run(f);
    }
}

Więcej informacji na temat języka tureckiego można znaleźć w tym poście na blogu dotyczącym Turcji .

Nie zdziwiłbym się słysząc, że są różne inne problemy z wielkimi literami wokół znaków elided itp. To tylko jeden przykład, który znam z całego serca ... częściowo dlatego, że ugryzł mnie wiele lat temu w Javie, gdzie byłem wyżej -casowanie łańcucha i porównywanie go z "MAIL". To nie działało tak dobrze w Turcji ...

Jon Skeet
źródło
47
haha, czytałem, że myślę… „Turcja nie ma w sobie litery„ i ””
Jeff Mercado
1
Zbliża się rok 2019 i mam Visual Studio sugerujące ımagejako nazwę pola dla ImageUnity 3D spamowanie wewnętrznego błędu konsoli Unable to find key name that matches 'rıght'w „angielskim” systemie Windows z regionalnymi ustawieniami daty i godziny dla Turcji. Wygląda na to, że czasami nawet Microsoft nie zdaje testu Turcji, język komputera nie jest nawet turecki, tylko lol.
Guney Ozsan
28

Odpowiedź Jona jest doskonała. Chciałem tylko dodać, że ToUpperInvariantto to samo, co dzwonienie ToUpper(CultureInfo.InvariantCulture).

To sprawia, że ​​przykład Jona jest trochę prostszy:

using System;
using System.Drawing;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;

public class Test
{
    [STAThread]
    static void Main()
    {
        string invariant = "iii".ToUpper(CultureInfo.InvariantCulture);
        string cultured = "iii".ToUpper(new CultureInfo("tr-TR"));

        Application.Run(new Form {
            Font = new Font("Times New Roman", 40),
            Controls = { 
                new Label { Text = invariant, Location = new Point(20, 20), AutoSize = true }, 
                new Label { Text = cultured, Location = new Point(20, 100), AutoSize = true }, 
            }
        });
    }
}

Użyłem też New Times Roman, ponieważ jest to fajniejsza czcionka.

Ustawiłem również właściwość Form's Fontzamiast dwóch Labelkontrolek, ponieważ Fontwłaściwość jest dziedziczona.

I zredukowałem kilka innych wierszy tylko dlatego, że lubię kod kompaktowy (na przykład nie produkcyjny).

W tej chwili naprawdę nie miałem nic lepszego do roboty.

Tergiver
źródło
5
„Odpowiedź Jona jest doskonała”. Porozmawiaj o zbędnym oświadczeniu. ;)
krillgar
1
Metoda ToUpper nie ma dla mnie żadnego przeciążenia parametrów? czy starsza wersja miała? Nie rozumiem
Emil
Nie wiem, jest to udokumentowane tutaj: msdn.microsoft.com/en-us/library/system.string.toupper.aspx
Tergiver
13

String.ToUpperi String.ToLowermoże dać różne wyniki w różnych kulturach. Najbardziej znanym przykładem jest turecki przykład , w którym zamiana małej litery „i” na wielkie litery nie daje łacińskiego „I” pisanego wielką literą, ale tureckie „I”.

Wielka litera I w zależności od kultury, górny rząd - małe litery, dolny rząd - duże litery

Jak dla mnie było to mylące nawet z powyższym obrazkiem ( źródło ), napisałem program (patrz kod źródłowy poniżej), aby zobaczyć dokładne dane wyjściowe dla przykładu tureckiego:

# Lowercase letters
Character              | UpperInvariant | UpperTurkish | LowerInvariant | LowerTurkish
English i - i (\u0069) | I (\u0049)     | I (\u0130)   | i (\u0069)     | i (\u0069)
Turkish i - ı (\u0131) | ı (\u0131)     | I (\u0049)   | ı (\u0131)     | ı (\u0131)

# Uppercase letters
Character              | UpperInvariant | UpperTurkish | LowerInvariant | LowerTurkish
English i - I (\u0049) | I (\u0049)     | I (\u0049)   | i (\u0069)     | ı (\u0131)
Turkish i - I (\u0130) | I (\u0130)     | I (\u0130)   | I (\u0130)     | i (\u0069)

Jak widzisz:

  1. Wielkie małe litery i małe wielkie litery dają różne wyniki dla kultury niezmiennej i kultury tureckiej.
  2. Wielkie i małe małe litery nie mają znaczenia, bez względu na kulturę.
  3. Culture.CultureInvariant pozostawia znaki tureckie bez zmian
  4. ToUpperi ToLowersą odwracalne, to znaczy małe litery po wielkich literach, doprowadzają go do pierwotnej postaci, o ile dla obu operacji użyto tej samej kultury.

Według MSDN , kultury for Char.ToUpperoraz Char.ToLowerturecka i azerska to jedyne kultury, których dotyczy problem, ponieważ są jedynymi, w których występują różnice w wielkości liter. W przypadku łańcuchów może to dotyczyć większej liczby kultur.


Kod źródłowy aplikacji konsolowej użytej do wygenerowania wyniku:

using System;
using System.Globalization;
using System.Linq;
using System.Text;

namespace TurkishI
{
    class Program
    {
        static void Main(string[] args)
        {
            var englishI = new UnicodeCharacter('\u0069', "English i");
            var turkishI = new UnicodeCharacter('\u0131', "Turkish i");

            Console.WriteLine("# Lowercase letters");
            Console.WriteLine("Character              | UpperInvariant | UpperTurkish | LowerInvariant | LowerTurkish");
            WriteUpperToConsole(englishI);
            WriteLowerToConsole(turkishI);

            Console.WriteLine("\n# Uppercase letters");
            var uppercaseEnglishI = new UnicodeCharacter('\u0049', "English i");
            var uppercaseTurkishI = new UnicodeCharacter('\u0130', "Turkish i");
            Console.WriteLine("Character              | UpperInvariant | UpperTurkish | LowerInvariant | LowerTurkish");
            WriteLowerToConsole(uppercaseEnglishI);
            WriteLowerToConsole(uppercaseTurkishI);

            Console.ReadKey();
        }

        static void WriteUpperToConsole(UnicodeCharacter character)
        {
            Console.WriteLine("{0,-9} - {1,10} | {2,-14} | {3,-12} | {4,-14} | {5,-12}",
                character.Description,
                character,
                character.UpperInvariant,
                character.UpperTurkish,
                character.LowerInvariant,
                character.LowerTurkish
            );
        }

        static void WriteLowerToConsole(UnicodeCharacter character)
        {
            Console.WriteLine("{0,-9} - {1,10} | {2,-14} | {3,-12} | {4,-14} | {5,-12}",
                character.Description,
                character,
                character.UpperInvariant,
                character.UpperTurkish,
                character.LowerInvariant,
                character.LowerTurkish
            );
        }
    }


    class UnicodeCharacter
    {
        public static readonly CultureInfo TurkishCulture = new CultureInfo("tr-TR");

        public char Character { get; }

        public string Description { get; }

        public UnicodeCharacter(char character) : this(character, string.Empty) {  }

        public UnicodeCharacter(char character, string description)
        {
            if (description == null) {
                throw new ArgumentNullException(nameof(description));
            }

            Character = character;
            Description = description;
        }

        public string EscapeSequence => ToUnicodeEscapeSequence(Character);

        public UnicodeCharacter LowerInvariant => new UnicodeCharacter(Char.ToLowerInvariant(Character));

        public UnicodeCharacter UpperInvariant => new UnicodeCharacter(Char.ToUpperInvariant(Character));

        public UnicodeCharacter LowerTurkish => new UnicodeCharacter(Char.ToLower(Character, TurkishCulture));

        public UnicodeCharacter UpperTurkish => new UnicodeCharacter(Char.ToUpper(Character, TurkishCulture));


        private static string ToUnicodeEscapeSequence(char character)
        {
            var bytes = Encoding.Unicode.GetBytes(new[] {character});
            var prefix = bytes.Length == 4 ? @"\U" : @"\u";
            var hex = BitConverter.ToString(bytes.Reverse().ToArray()).Replace("-", string.Empty);
            return $"{prefix}{hex}";
        }

        public override string ToString()
        {
            return $"{Character} ({EscapeSequence})";
        }
    }
}
krzychu
źródło
Tabela przypadków była bardzo pomocna. Dzięki!
VoteCoffee
2

nie ma różnicy w języku angielskim. tylko w kulturze tureckiej można znaleźć różnicę.

Stefanvds
źródło
14
I jesteś pewien, że turecki jest jedyną kulturą na świecie, która ma inne zasady dotyczące wielkich liter niż angielski? Trudno mi w to uwierzyć.
Joel Mueller
3
Turecki jest najczęściej używanym przykładem, ale nie jedynym. I to język, a nie kultura ma cztery różne ja. Wciąż +1 dla języka tureckiego.
Armstrongest
na pewno muszą być inni. i tak większość ppl nigdy nie spotka się z tymi językami w programowaniu
Stefanvds
9
Pewnie, że tak. Aplikacje internetowe są otwarte na cały świat i dobrze jest ustawić swoje parametry. A co, jeśli pracujesz na starszej bazie danych, która nie obsługuje formatu Unicode? Jakie znaki zaakceptujesz jako nazwę użytkownika? A co, jeśli musisz wprowadzić nazwy klientów do starszego systemu ERP opartego na języku COBOL? Wiele przypadków, w których kultura jest ważna. Nie wspominając o datach i liczbach. 4.54 jest napisane 4,54 w niektórych językach. Udawanie, że te inne języki nie istnieją, na dłuższą metę nie zaprowadzi cię zbyt daleko.
Armstrongest
oczywiście kultury są ważne dla dat i liczb, po prostu mówię, że większość ppl nigdy nie spotka się z językami, które mają różne wyniki w toUpper i toUpperInvariant.
Stefanvds