Was ist in C # der Unterschied zwischen ToUpper () und ToUpperInvariant ()?

133

Was ist in C # der Unterschied zwischen ToUpper()und ToUpperInvariant()?

Können Sie ein Beispiel geben, bei dem die Ergebnisse unterschiedlich sein könnten?

Lill Lansey
quelle
3
[Organisation] Sollte diese Frage den Tag "Internationalisierung" haben?
Jasso

Antworten:

154

ToUppernutzt die aktuelle Kultur. ToUpperInvariantnutzt die invariante Kultur.

Das kanonische Beispiel ist die Türkei, wo der Großbuchstabe von "i" nicht "I" ist.

Beispielcode, der den Unterschied zeigt:

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);
    }
}

Weitere Informationen zum Türkischen finden Sie in diesem Blog-Beitrag zum Türkei-Test .

Es würde mich nicht wundern zu hören, dass es verschiedene andere Großschreibungsprobleme bei elidierten Charakteren usw. gibt. Dies ist nur ein Beispiel, das ich aus dem Kopf kenne ... teilweise, weil es mich vor Jahren in Java gebissen hat, wo ich oben war - einen String umhüllen und mit "MAIL" vergleichen. Das hat in der Türkei nicht so gut funktioniert ...

Jon Skeet
quelle
45
haha ich habe diesen Gedanken gelesen ... "'Türkei' hat keinen Buchstaben 'i' drin"
Jeff Mercado
Es ist fast 2019 und ich habe Visual Studio ımageals Feldnamen für Imageund Unity 3D vorgeschlagen, einen internen Fehler an die Konsole Unable to find key name that matches 'rıght'auf einem "englischen" Windows mit regionalen Einstellungen für die Türkei für Datum und Uhrzeit zu spammen. Es sieht so aus, als ob manchmal sogar Microsoft den Türkei-Test nicht besteht. Die Sprache eines PCs ist nicht einmal Türkisch, nur lol.
Guney Ozsan
28

Jons Antwort ist perfekt. Ich wollte nur hinzufügen, dass ToUpperInvariantdas dasselbe ist wie anrufen ToUpper(CultureInfo.InvariantCulture).

Das macht Jons Beispiel etwas einfacher:

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 }, 
            }
        });
    }
}

Ich habe auch New Times Roman verwendet, weil es eine coolere Schriftart ist.

Ich habe auch die Eigenschaft Form's Fontanstelle der beiden LabelSteuerelemente festgelegt, da die FontEigenschaft vererbt wird.

Und ich habe ein paar andere Zeilen reduziert, nur weil ich kompakten Code (zum Beispiel keinen Produktionscode) mag.

Ich hatte im Moment wirklich nichts Besseres zu tun.

Tergiver
quelle
5
"Jons Antwort ist perfekt." Sprechen Sie über eine redundante Aussage. ;)
Krillgar
1
ToUpper-Methode hat keine Parameterüberladung für mich? hatte ältere Version? Ich
verstehe
Ich weiß nicht, es ist hier dokumentiert: msdn.microsoft.com/en-us/library/system.string.toupper.aspx
Tergiver
12

String.ToUpperund String.ToLowerkann bei unterschiedlichen Kulturen unterschiedliche Ergebnisse liefern. Das bekannteste Beispiel ist das türkische Beispiel , bei dem die Konvertierung von lateinischem "i" in Großbuchstaben nicht zu einem großgeschriebenen lateinischen "I" führt, sondern zum türkischen "I".

Großschreibung von I je nach Kultur, obere Reihe - Kleinbuchstaben, untere Reihe - Großbuchstaben

Was mich selbst mit dem obigen Bild ( Quelle ) verwirrte , schrieb ich ein Programm (siehe Quellcode unten), um die genaue Ausgabe für das türkische Beispiel zu sehen:

# 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)

Wie du siehst:

  1. Großbuchstaben in Großbuchstaben und Großbuchstaben in Kleinbuchstaben führen zu unterschiedlichen Ergebnissen für die invariante Kultur und die türkische Kultur.
  2. Großbuchstaben in Großbuchstaben und Kleinbuchstaben in Kleinbuchstaben haben keine Auswirkung, unabhängig von der Kultur.
  3. Culture.CultureInvariant Lässt die türkischen Zeichen wie sie sind
  4. ToUpperund ToLowersind reversibel, dh wenn ein Zeichen nach dem Großbuchstaben in Kleinbuchstaben geschrieben wird, wird es in die ursprüngliche Form gebracht, solange für beide Operationen dieselbe Kultur verwendet wurde.

Laut MSDN sind für Char.ToUpper und Char.ToLower Türkisch und Aserbaidschanisch die einzigen betroffenen Kulturen, da sie die einzigen sind, die Unterschiede in der Groß- und Kleinschreibung aufweisen. Bei Saiten sind möglicherweise mehr Kulturen betroffen.


Quellcode einer Konsolenanwendung, mit der die Ausgabe generiert wird:

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
quelle
Die Falltabelle war sehr hilfreich. Vielen Dank!
VoteCoffee
2

Es gibt keinen Unterschied in Englisch. Nur in der türkischen Kultur kann ein Unterschied festgestellt werden.

Stefanvds
quelle
13
Und Sie sind sicher, dass Türkisch die einzige Kultur der Welt ist, die andere Regeln für Großbuchstaben als Englisch hat? Ich finde das schwer zu glauben.
Joel Mueller
3
Türkisch ist das am häufigsten verwendete Beispiel, aber nicht das einzige. Und es ist die Sprache, nicht die Kultur, die vier verschiedene Ichs hat. Trotzdem +1 für Türkisch.
Armstrongest
sicher muss es einige andere geben. Die meisten Leute werden diese Sprachen in der Programmierung sowieso nie treffen
Stefanvds
8
Sicher werden sie. Webanwendungen sind für den Globus offen und es ist gut, Ihre Parameter festzulegen. Was ist, wenn Sie mit einer Legacy-Datenbank arbeiten, die keinen Unicode ausführt? Welche Zeichen akzeptieren Sie als Benutzernamen? Was ist, wenn Sie Kundennamen in ein auf COBOL basierendes Legacy-ERP eingeben müssen? Viele Fälle, in denen die Kultur wichtig ist. Ganz zu schweigen von Daten und Zahlen. 4.54 ist 4,54 in einigen Sprachen geschrieben. Wenn Sie so tun, als gäbe es diese anderen Sprachen nicht, werden Sie auf lange Sicht nicht weit kommen.
Armstrongest
Offensichtlich sind Kulturen wichtig für Daten und Zahlen. Ich sage nur, dass die meisten Menschen niemals die Sprachen treffen werden, die in toUpper und toUpperInvariant ein anderes Ergebnis haben.
Stefanvds