2010-08-23 24 views

Respuesta

117

ToUpper usa la cultura actual. ToUpperInvariant usa la cultura invariante.

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

Código de ejemplo 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 más información sobre turco, ver este Turkey Test blog post.

No me sorprendería saber que existen otros problemas de mayúsculas en torno a los caracteres elásticos, etc. Este es solo un ejemplo que sé de sobra ... en parte porque me mordió hace años en Java, donde estaba haciendo una cadena superior y comparándola con "CORREO". Eso no funcionó tan bien en Turquía ...

+34

jaja Leí eso pensando ... "'Turquía' no tiene una letra 'yo' en él" –

+3

Violín que ilustra lo mismo: https://dotnetfiddle.net/x3uqwa – KorsG

3

no hay ninguna diferencia en Inglés. solo en la cultura turca se puede encontrar una diferencia.

+12

Y está seguro de que el turco es el única cultura en el mundo que tiene diferentes reglas para mayúsculas que inglés? Me parece difícil de creer. –

+2

El turco es el ejemplo más utilizado, pero no el único. Y es el lenguaje, no la cultura, lo que tiene cuatro I diferentes. Aún así, +1 para turco. – Armstrongest

+0

seguro que debe haber algunos otros. la mayoría de las personas nunca se encontrarán con esos idiomas en la programación de todos modos – Stefanvds

19

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

Eso hace que el ejemplo de Jon 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 }, 
      } 
     }); 
    } 
} 

que también utilizaron Times New Roman porque es un tipo de letra más fresco.

Asimismo, establecer la propiedad Font la Form 's en lugar de los dos controles Label porque la propiedad Font se hereda.

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

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

+4

"La respuesta de Jon es perfecta". Habla sobre una declaración redundante. ;) – krillgar

+1

El método ToUpper no tiene ninguna sobrecarga de parámetros para mí? Qué versión más antigua tiene? No lo entiendo – batmaci

+0

No lo sé, está documentado aquí: https://msdn.microsoft.com/en-us/library/system.string.toupper.aspx – Tergiver

3

String.ToUpper y String.ToLower pueden dar resultados diferentes según las diferentes culturas. El ejemplo más conocido es the Turkish example, por lo que la conversión de "i" en mayúscula en minúscula a mayúscula no da como resultado una "I" en mayúscula en mayúscula, sino en "I" en turco.

Capitalization of I depending on culture, upper row - lower case letters, lower row - upper case letters

En cuanto a mí era confuso, incluso con la imagen de arriba (source), que escribió un programa (ver código fuente abajo) para ver la salida exacta para el 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 se puede ver:

  1. Uppercasing letras minúsculas y en minúscula las letras mayúsculas dar diferentes resultados de referencia cultural de todos y el culto de Turquía ure.
  2. Las letras mayúsculas superpuestas y las letras minúsculas en minúsculas no tienen ningún efecto, independientemente de la cultura.
  3. Culture.CultureInvariant deja a los caracteres turcos como es
  4. ToUpperToLower y son reversibles, es decir un carácter en minúscula después uppercasing él, lo lleva a la forma original, siempre que para ambas operaciones se utilizó la misma cultura.

Según MSDN, por Char.ToUpper y Char.ToLower turco y azerbaiyano son los únicos cultivos afectados, ya que son los únicos que tienen diferencias de la carcasa de un solo carácter. Para cuerdas, puede haber más culturas afectadas.


El código fuente de una aplicación de consola que se utiliza 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})"; 
     } 
    } 
} 
Cuestiones relacionadas