En C #, ¿cuál es la diferencia entre ToUpper () y ToUpperInvariant ()?

133

En C #, ¿cuál es la diferencia entre ToUpper()y ToUpperInvariant()?

¿Puedes dar un ejemplo donde los resultados podrían ser diferentes?

Lill Lansey
fuente
3
[Organización] ¿Esta pregunta debería tener la etiqueta "internacionalización"?
jasso

Respuestas:

154

ToUpperusa la cultura actual. ToUpperInvariantusa la cultura invariante.

El ejemplo canónico es Turquía, donde la mayúscula de "i" no es "I".

Código de muestra que muestra la diferencia:

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

Para obtener más información sobre el turco, vea esta publicación del blog Prueba de Turquía .

No me sorprendería saber que hay varios otros problemas de capitalización en torno a los caracteres elididos, etc. Este es solo un ejemplo que conozco fuera de mi cabeza ... en parte porque me mordió hace años en Java, donde era superior -envolviendo una cadena y comparándola con "CORREO". Eso no funcionó tan bien en Turquía ...

Jon Skeet
fuente
45
jaja lo leí pensando ... "'Turquía' no tiene una letra 'i' en ella"
Jeff Mercado
Es casi 2019 y tengo a Visual Studio sugiriendo ımagecomo nombre de campo Imagey Unity 3D enviando un error interno a la consola Unable to find key name that matches 'rıght'en un Windows "inglés" con configuraciones regionales de Turquía para fecha y hora. Parece que a veces incluso Microsoft falla la prueba de Turquía, el idioma de una PC ni siquiera es turco, solo jajaja.
Guney Ozsan
28

La respuesta de Jon es perfecta. Solo quería agregar que ToUpperInvariantes lo mismo que llamar ToUpper(CultureInfo.InvariantCulture).

Eso hace que el ejemplo de Jon sea un poco más 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 }, 
            }
        });
    }
}

También usé New Times Roman porque es una fuente más genial.

También configuré la propiedad de Form's en Fontlugar de los dos Labelcontroles porque la Fontpropiedad se hereda.

Y reduje algunas otras líneas solo porque me gusta el código compacto (ejemplo, no producción).

Realmente no tenía nada mejor que hacer en este momento.

Tergiver
fuente
55
"La respuesta de Jon es perfecta". Hable acerca de una declaración redundante. ;)
krillgar
1
¿El método ToUpper no tiene ninguna sobrecarga de parámetros para mí? tenía la versión anterior? No lo entiendo
batmaci
No sé, está documentado aquí: msdn.microsoft.com/en-us/library/system.string.toupper.aspx
Tergiver
12

String.ToUppery String.ToLowerpuede dar diferentes resultados dados diferentes culturas. El ejemplo más conocido es el ejemplo turco , para el cual la conversión de minúsculas latinas "i" a mayúsculas, no da como resultado una "I" latina mayúscula, sino la "I" turca.

Capitalización de I dependiendo de la cultura, fila superior - letras minúsculas, fila inferior - letras mayúsculas

En cuanto a mí, fue confuso incluso con la imagen de arriba ( fuente ), escribí un programa (vea el código fuente a continuación) para ver la salida exacta del ejemplo turco:

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

Como puedes ver:

  1. Las letras mayúsculas y minúsculas y las mayúsculas minúsculas dan resultados diferentes para la cultura invariante y la cultura turca.
  2. Las letras mayúsculas en mayúsculas y las minúsculas en minúsculas no tienen ningún efecto, sin importar cuál sea la cultura.
  3. Culture.CultureInvariant deja los caracteres turcos como están
  4. ToUpper y ToLower son reversibles, es decir, un carácter en minúsculas después de ponerlo en mayúscula, lo lleva a la forma original, siempre y cuando para ambas operaciones se haya utilizado la misma cultura.

Según MSDN , para Char.ToUpper y Char.ToLower, el turco y el azerí son las únicas culturas afectadas porque son las únicas con diferencias de carcasa de un solo carácter. Para las cuerdas, puede haber más culturas afectadas.


Código fuente de una aplicación de consola utilizada para generar la salida:

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
fuente
La tabla de casos fue muy útil. ¡Gracias!
VoteCoffee
2

No hay diferencia en inglés. solo en la cultura turca se puede encontrar una diferencia.

Stefanvds
fuente
13
¿Y está seguro de que el turco es la única cultura en el mundo que tiene reglas diferentes para las mayúsculas que el inglés? Me parece difícil de creer.
Joel Mueller
3
El turco es el ejemplo más utilizado, pero no el único. Y es el idioma, no la cultura, el que tiene cuatro yoes diferentes. Aún así, +1 para turco.
Armstrongest
Seguro que debe haber algunos otros. la mayoría de las personas nunca conocerán esos lenguajes en la programación de todos modos
Stefanvds
8
Claro que lo harán. Las aplicaciones web están abiertas al mundo y es bueno establecer sus parámetros. ¿Qué sucede si está operando en una base de datos heredada que no funciona con Unicode? ¿Qué caracteres aceptarás como nombre de usuario? ¿Qué sucede si tiene que poner los nombres de los clientes en un ERP heredado construido en COBOL? Muchos casos donde la cultura es importante. Sin mencionar fechas y números. 4.54 está escrito 4.54 en algunos idiomas. Pretender que esos otros idiomas no existen no te llevará muy lejos a la larga.
Armstrongest el
obviamente, las culturas son importantes para las fechas y los números, solo digo que la mayoría de las personas nunca conocerán los idiomas que tienen un resultado diferente en toUpper y toUpperInvariant.
Stefanvds