En C # quelle est la différence entre ToUpper () et ToUpperInvariant ()?

133

En C #, quelle est la différence entre ToUpper()et ToUpperInvariant()?

Pouvez-vous donner un exemple où les résultats pourraient être différents?

Lill Lansey
la source
3
[Organisation] Cette question devrait-elle avoir la balise «internationalisation»?
jasso

Réponses:

154

ToUpperutilise la culture actuelle. ToUpperInvariantutilise la culture invariante.

L'exemple canonique est la Turquie, où la majuscule de «i» n'est pas «je».

Exemple de code montrant la différence:

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

Pour en savoir plus sur le turc, consultez cet article de blog Turkey Test .

Je ne serais pas surpris d'entendre qu'il y a divers autres problèmes de capitalisation autour des personnages élidés, etc. Ce n'est qu'un exemple que je connais d'emblée ... en partie parce que cela m'a mordu il y a des années à Java, où j'étais supérieur -caser une chaîne et la comparer avec "MAIL". Cela n'a pas si bien fonctionné en Turquie ...

Jon Skeet
la source
45
haha j'ai lu cela en pensant ... "'Turquie' n'a pas de lettre 'i' dedans"
Jeff Mercado
Nous sommes presque 2019 et je ımagedemande à Visual Studio de suggérer comme nom de champ Imageet de spam Unity 3D une erreur interne à la console Unable to find key name that matches 'rıght'sur un Windows "anglais" avec les paramètres régionaux de Turquie pour la date et l'heure. On dirait que parfois même Microsoft échoue au test de la Turquie, la langue d'un PC n'est même pas le turc, juste lol.
Guney Ozsan
28

La réponse de Jon est parfaite. Je voulais juste ajouter que ToUpperInvariantc'est la même chose que d'appeler ToUpper(CultureInfo.InvariantCulture).

Cela rend l'exemple de Jon un peu plus simple:

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

J'ai aussi utilisé New Times Roman car c'est une police plus cool.

J'ai également mis le Form'sFont propriété au lieu des deux Labelcontrôles car la Fontpropriété est héritée.

Et j'ai réduit quelques autres lignes simplement parce que j'aime le code compact (exemple, pas de production).

Je n'avais vraiment rien de mieux à faire pour le moment.

Tergiver
la source
5
"La réponse de Jon est parfaite." Parlez d'une déclaration redondante. ;)
krillgar
1
La méthode ToUpper n'a pas de surcharge de paramètres pour moi? une ancienne version avait-elle? Je ne comprends pas
batmaci
Je ne sais pas, il est documenté ici: msdn.microsoft.com/en-us/library/system.string.toupper.aspx
Tergiver
12

String.ToUpperet String.ToLowerpeut donner des résultats différents selon les cultures. L'exemple le plus connu est l'exemple turc , pour lequel la conversion du latin minuscule "i" en majuscule ne se traduit pas par un "I" latin majuscule, mais par le "I" turc.

Capitalisation du I en fonction de la culture, ligne supérieure - lettres minuscules, ligne inférieure - lettres majuscules

Quant à moi, c'était déroutant même avec l'image ci-dessus ( source ), j'ai écrit un programme (voir le code source ci-dessous) pour voir la sortie exacte de l'exemple turc:

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

Comme vous pouvez le voir:

  1. Les lettres minuscules majuscules et les lettres majuscules minuscules donnent des résultats différents pour la culture invariante et la culture turque.
  2. Les majuscules et les minuscules n'ont aucun effet, quelle que soit la culture.
  3. Culture.CultureInvariant laisse les caractères turcs tels quels
  4. ToUpperet ToLowersont réversibles, c'est-à-dire en minuscules un caractère après l'avoir mis en majuscules, le ramène à la forme d'origine, tant que pour les deux opérations la même culture a été utilisée.

Selon MSDN , pour Char.ToUpper et Char.ToLower, le turc et l'azéri sont les seules cultures affectées car ce sont les seules avec des différences de casse à un seul caractère. Pour les chaînes, d'autres cultures peuvent être affectées.


Code source d'une application console utilisée pour générer la sortie:

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
la source
Le tableau des cas était très utile. Merci!
VoteCoffee
2

il n'y a pas de différence en anglais. ce n'est que dans la culture turque qu'une différence peut être trouvée.

Stefanvds
la source
13
Et vous êtes sûr que le turc est la seule culture au monde qui a des règles différentes pour les majuscules de l'anglais? Je trouve cela difficile à croire.
Joel Mueller
3
Le turc est l'exemple le plus souvent utilisé, mais pas le seul. Et c'est la langue, pas la culture qui a quatre Moi différents. Pourtant, +1 pour le turc.
Armstrongest
bien sûr, il doit y en avoir d'autres. la plupart des personnes ne rencontreront jamais jamais ces langages dans la programmation de toute façon
Stefanvds
8
Bien sûr qu'ils le feront. Les applications Web sont ouvertes sur le monde et il est bon de définir vos paramètres. Que faire si vous utilisez une base de données héritée qui n'utilise pas l'Unicode? Quels caractères accepterez-vous comme nom d'utilisateur? Que faire si vous devez entrer les noms des clients dans un ERP hérité basé sur COBOL? Beaucoup de cas où la culture est importante. Sans parler des dates et des chiffres. 4.54 s'écrit 4,54 dans certaines langues. Prétendre que ces autres langues n'existent pas ne vous mènera pas très loin sur le long terme.
Armstrongest
évidemment les cultures sont importantes pour les dates et les nombres, je dis juste que la plupart des personnes ne rencontreront jamais les langues qui ont un résultat différent dans toUpper et toUpperInvariant.
Stefanvds