Em C #, qual é a diferença entre ToUpper () e ToUpperInvariant ()?

133

Em C #, qual é a diferença entre ToUpper()e ToUpperInvariant()?

Você pode dar um exemplo em que os resultados podem ser diferentes?

Lill Lansey
fonte
3
[Organização] Esta pergunta deve ter a tag "internacionalização"?
precisa saber é

Respostas:

154

ToUpperusa a cultura atual. ToUpperInvariantusa a cultura invariável.

O exemplo canônico é a Turquia, onde a letra maiúscula de "i" não é "I".

Código de exemplo mostrando a diferença:

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 saber mais sobre turco, consulte esta postagem no blog Turkey Test .

Eu não ficaria surpreso ao saber que existem vários outros problemas de maiúsculas em torno de personagens elidificados etc. -casando uma string e comparando-a com "MAIL". Isso não funcionou tão bem na Turquia ...

Jon Skeet
fonte
45
haha eu li esse pensamento ... "'Turquia' não tem uma letra 'i'"
Jeff Mercado
É quase 2019 e estou tendo o Visual Studio sugerindo ımagecomo um nome de campo para o ImageUnity 3D enviar um spam para um erro interno no console Unable to find key name that matches 'rıght'em um Windows "inglês" com as configurações regionais da Turquia para data e hora. Parece que, às vezes, até a Microsoft falha no teste da Turquia, o idioma de um PC nem sequer é turco, apenas risos.
Guney Ozsan
28

A resposta de Jon é perfeita. Eu só queria acrescentar que ToUpperInvarianté o mesmo que ligar ToUpper(CultureInfo.InvariantCulture).

Isso torna o exemplo de Jon um pouco mais simples:

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

Eu também usei o New Times Roman porque é uma fonte mais legal.

Eu também definir o Form's Fontpropriedade em vez dos dois Labelcontroles porque a Fontpropriedade é herdada.

E reduzi algumas outras linhas apenas porque gosto de código compacto (por exemplo, não de produção).

Eu realmente não tinha nada melhor para fazer no momento.

Tergiver
fonte
5
"A resposta de Jon é perfeita." Fale sobre uma declaração redundante. ;)
krillgar
1
O método ToUpper não tem sobrecarga de parâmetro para mim? a versão mais antiga tinha? Eu não entendi
batmaci
Eu não sei, ele está documentado aqui: msdn.microsoft.com/en-us/library/system.string.toupper.aspx
Tergiver
12

String.ToUppere String.ToLowerpode dar resultados diferentes, dadas culturas diferentes. O exemplo mais conhecido é o exemplo turco , para o qual converter latim minúsculo "i" em maiúsculo não resulta em latim maiúsculo "I", mas no turco "I".

Letras maiúsculas em I, dependendo da cultura, linha superior - letras minúsculas, linha inferior - letras maiúsculas

Quanto a mim, foi confuso, mesmo com a imagem acima ( fonte ), escrevi um programa (veja o código-fonte abaixo) para ver a saída exata do exemplo 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 você pode ver:

  1. Letras maiúsculas e minúsculas e maiúsculas fornecem resultados diferentes para a cultura invariável e a cultura turca.
  2. Letras maiúsculas e minúsculas não têm efeito, não importa qual seja a cultura.
  3. Culture.CultureInvariant deixa os caracteres turcos como estão
  4. ToUppere ToLowersão reversíveis, que colocam um caractere em minúsculas e depois em maiúsculas, o traz para a forma original, desde que para ambas as operações a mesma cultura tenha sido usada.

De acordo com o MSDN , para Char.ToUpper e Char.ToLower Turco e Azeri são as únicas culturas afetadas porque são as únicas com diferenças de revestimento de caractere único. Para strings, pode haver mais culturas afetadas.


Código-fonte de um aplicativo de console usado para gerar a saída:

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
fonte
A tabela de casos foi muito útil. Obrigado!
VoteCoffee
2

não há diferença em inglês. somente na cultura turca é possível encontrar uma diferença.

Stefanvds
fonte
13
E você tem certeza de que o turco é a única cultura no mundo que possui regras diferentes para maiúsculas que o inglês? Acho isso difícil de acreditar.
Joel Mueller
3
O turco é o exemplo mais usado, mas não o único. E é a língua, não a cultura que tem quatro E's diferentes. Ainda assim, +1 para turco.
Armstrongest
claro que deve haver outros. a maioria dos ppl nunca vai atender a essas linguagens de programação de qualquer maneira
Stefanvds
8
Claro que sim. Os aplicativos da Web são abertos ao mundo e é bom definir seus parâmetros. E se você estiver operando em um banco de dados herdado que não executa unicode? Quais caracteres você aceita como nome de usuário? E se você tiver que colocar os nomes dos Clientes em um ERP herdado baseado em COBOL? Muitos casos em que a cultura é importante. Sem mencionar datas e números. 4.54 está escrito 4,54 em alguns idiomas. Fingir que essas outras línguas não existem não o levará muito longe a longo prazo.
Armstrongest
Obviamente, as culturas são importantes para datas e números. Só estou dizendo que a maioria das pessoas nunca encontrará os idiomas com resultados diferentes em toUpper e toUpperInvariant.
Stefanvds