Procedimientos recomendados para el uso de cadenas en .NETBest Practices for Using Strings in .NET

.NET proporciona una gran compatibilidad para desarrollar aplicaciones localizadas y globalizadas, y simplifica la aplicación de las convenciones de la referencia cultural actual o de una referencia cultural concreta al realizar operaciones comunes como ordenar y mostrar cadenas..NET provides extensive support for developing localized and globalized applications, and makes it easy to apply the conventions of either the current culture or a specific culture when performing common operations such as sorting and displaying strings. Pero ordenar o comparar cadenas no es siempre una operación dependiente de la referencia cultural.But sorting or comparing strings is not always a culture-sensitive operation. Por ejemplo, las cadenas usadas internamente por una aplicación normalmente se deben administrar de forma idéntica en todas las referencias culturales.For example, strings that are used internally by an application typically should be handled identically across all cultures. Cuando los datos de cadenas independientes de la referencia cultural (como etiquetas XML, etiquetas HTML, nombres de usuario, rutas de acceso de archivos y nombres de objetos del sistema) se interpretan como si fueran dependientes de la referencia cultural, el código de aplicación puede estar sujeto a errores imperceptibles, un rendimiento inadecuado y, en algunos casos, a problemas de seguridad.When culturally independent string data, such as XML tags, HTML tags, user names, file paths, and the names of system objects, are interpreted as if they were culture-sensitive, application code can be subject to subtle bugs, poor performance, and, in some cases, security issues.

En este tema, se examinan los métodos de ordenación, comparación y uso de mayúsculas y minúsculas de cadenas de .NET, se presentan recomendaciones para seleccionar un método adecuado de control de cadenas y se proporciona información adicional sobre los métodos de control de cadenas.This topic examines the string sorting, comparison, and casing methods in .NET, presents recommendations for selecting an appropriate string-handling method, and provides additional information about string-handling methods. También se examina cómo se usan para la presentación y el almacenamiento los datos con formato, como los datos numéricos y los datos de fecha y hora.It also examines how formatted data, such as numeric data and date and time data, is handled for display and for storage.

Este tema contiene las siguientes secciones:This topic contains the following sections:

Recomendaciones sobre el uso de cadenasRecommendations for String Usage

Cuando desarrolle con .NET, siga estas recomendaciones sencillas a la hora de usar cadenas:When you develop with .NET, follow these simple recommendations when you use strings:

Evite lo siguiente cuando use cadenas:Avoid the following practices when you use strings:

  • No emplee sobrecargas que no especifiquen explícita o implícitamente las reglas de comparación de cadenas para las operaciones de cadena.Do not use overloads that do not explicitly or implicitly specify the string comparison rules for string operations.

  • No use operaciones de cadena basadas en StringComparison.InvariantCulture en la mayoría de los casos.Do not use string operations based on StringComparison.InvariantCulture in most cases. Una de las pocas excepciones es cuando vaya a conservar datos lingüísticamente significativos pero válidos culturalmente.One of the few exceptions is when you are persisting linguistically meaningful but culturally agnostic data.

  • No emplee ninguna sobrecarga del método String.Compare o CompareTo y pruebe si se devuelve un valor cero para determinar si dos cadenas son iguales.Do not use an overload of the String.Compare or CompareTo method and test for a return value of zero to determine whether two strings are equal.

  • No use el formato dependiente de la referencia cultural para conservar datos numéricos o datos de fecha y hora en formato de cadena.Do not use culture-sensitive formatting to persist numeric data or date and time data in string form.

Volver al principioBack to top

Especificar comparaciones de cadenas explícitamenteSpecifying String Comparisons Explicitly

La mayoría de los métodos de manipulación de cadenas de .NET están sobrecargados.Most of the string manipulation methods in .NET are overloaded. Normalmente, una o más sobrecargas aceptan la configuración predeterminada, mientras que otras no aceptan ningún valor predeterminado y en su lugar definen la manera precisa en la que se van a comparar o manipular las cadenas.Typically, one or more overloads accept default settings, whereas others accept no defaults and instead define the precise way in which strings are to be compared or manipulated. La mayoría de los métodos que no confían en los valores predeterminados incluye un parámetro de tipo StringComparison, que es una enumeración que especifica explícitamente reglas para la comparación de cadenas por referencia cultural y uso de mayúsculas y minúsculas.Most of the methods that do not rely on defaults include a parameter of type StringComparison, which is an enumeration that explicitly specifies rules for string comparison by culture and case. En la tabla siguiente se describen los miembros de la enumeración StringComparison .The following table describes the StringComparison enumeration members.

Miembro de StringComparisonStringComparison member DescripciónDescription
CurrentCulture Realiza una comparación con distinción entre mayúsculas y minúsculas usando la referencia cultural actual.Performs a case-sensitive comparison using the current culture.
CurrentCultureIgnoreCase Realiza una comparación sin distinción entre mayúsculas y minúsculas usando la referencia cultural actual.Performs a case-insensitive comparison using the current culture.
InvariantCulture Realiza una comparación con distinción entre mayúsculas y minúsculas usando la referencia cultural de todos los idiomas.Performs a case-sensitive comparison using the invariant culture.
InvariantCultureIgnoreCase Realiza una comparación sin distinción entre mayúsculas y minúsculas usando la referencia cultural de todos los idiomas.Performs a case-insensitive comparison using the invariant culture.
Ordinal Realiza una comparación ordinal.Performs an ordinal comparison.
OrdinalIgnoreCase Realiza una comparación ordinal sin distinción entre mayúsculas y minúsculas.Performs a case-insensitive ordinal comparison.

Por ejemplo, el método IndexOf , que devuelve el índice de una subcadena en un objeto String que coincide con un carácter o una cadena, tiene nueve sobrecargas:For example, the IndexOf method, which returns the index of a substring in a String object that matches either a character or a string, has nine overloads:

Se recomienda seleccionar una sobrecarga que no use valores predeterminados, por las razones siguientes:We recommend that you select an overload that does not use default values, for the following reasons:

  • Algunas sobrecargas con parámetros predeterminados (las que buscan un valor Char en la instancia de la cadena) realizan una comparación ordinal, mientras que otras (las que buscan una cadena en la instancia de la cadena) son dependientes de la referencia cultural.Some overloads with default parameters (those that search for a Char in the string instance) perform an ordinal comparison, whereas others (those that search for a string in the string instance) are culture-sensitive. Es difícil recordar qué método usa cada valor predeterminado y resulta fácil confundir las sobrecargas.It is difficult to remember which method uses which default value, and easy to confuse the overloads.

  • La intención del código que usa valores predeterminados para las llamadas al método no está clara.The intent of the code that relies on default values for method calls is not clear. En el ejemplo siguiente, en el cual se usan valores predeterminados, es difícil saber si el desarrollador pretendía realizar una comparación ordinal o lingüística de dos cadenas, o si había alguna diferencia al usar mayúsculas y minúsculas entre protocol y "http" que pudiera hacer que la prueba de igualdad devolviera el valor false.In the following example, which relies on defaults, it is difficult to know whether the developer actually intended an ordinal or a linguistic comparison of two strings, or whether a case difference between protocol and "http" might cause the test for equality to return false.

    string protocol = GetProtocol(url);       
    if (String.Equals(protocol, "http")) {
       // ...Code to handle HTTP protocol.
    }
    else {
       throw new InvalidOperationException();
    }
    
    Dim protocol As String = GetProtocol(url)       
    If String.Equals(protocol, "http") Then
       ' ...Code to handle HTTP protocol.
    Else
       Throw New InvalidOperationException()
    End If   
    

En general, se recomienda llamar a un método que no use los valores predeterminados, ya que hace que la intención del código no sea ambigua.In general, we recommend that you call a method that does not rely on defaults, because it makes the intent of the code unambiguous. Esto, a su vez, hace el código más legible y más fácil de depurar y mantener.This, in turn, makes the code more readable and easier to debug and maintain. En el ejemplo siguiente se abordan las cuestiones que se derivan del ejemplo anterior.The following example addresses the questions raised about the previous example. Indica claramente que se usa la comparación ordinal y que se omiten las diferencias en cuanto al uso de mayúsculas y minúsculas.It makes it clear that ordinal comparison is used and that differences in case are ignored.

string protocol = GetProtocol(url);       
if (String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase)) {
   // ...Code to handle HTTP protocol.
}
else {
   throw new InvalidOperationException();
}
Dim protocol As String = GetProtocol(url)       
If String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase) Then
   ' ...Code to handle HTTP protocol.
Else
   Throw New InvalidOperationException()
End If   

Volver al principioBack to top

Detalles de la comparación de cadenasThe Details of String Comparison

La comparación de cadenas es el corazón de muchas operaciones relacionadas con cadenas, especialmente la ordenación y la comprobación de igualdad.String comparison is the heart of many string-related operations, particularly sorting and testing for equality. Las cadenas se ordenan en un orden determinado: si "mi" aparece antes que "cadena" en una lista ordenada de cadenas, "mi" debe compararse como menor o igual que "cadena".Strings sort in a determined order: If "my" appears before "string" in a sorted list of strings, "my" must compare less than or equal to "string". Además, la comparación define la igualdad implícitamente.Additionally, comparison implicitly defines equality. La operación de comparación devuelve cero para las cadenas que considera iguales.The comparison operation returns zero for strings it deems equal. Una buena interpretación es que ninguna cadena es menor que otra.A good interpretation is that neither string is less than the other. La mayoría de las operaciones significativas que implican cadenas incluyen uno o ambos de estos procedimientos: comparar con otra cadena y ejecutar una operación de ordenación bien definida.Most meaningful operations involving strings include one or both of these procedures: comparing with another string, and executing a well-defined sort operation.

Nota

Puede descargar las tablas de pesos de ordenación, un conjunto de archivos de texto que contienen información sobre los pesos de caracteres que se usan en las operaciones de ordenación y comparación para los sistemas operativos Windows, además de la tabla de elementos de intercalación Unicode predeterminada, que es la última versión de la tabla de pesos de ordenación para Linux y macOS.You can download the Sorting Weight Tables, a set of text files that contain information on the character weights used in sorting and comparison operations for Windows operating systems, and the Default Unicode Collation Element Table, the latest version of the sort weight table for Linux and macOS. La versión específica de la tabla de pesos de ordenación en Linux y macOS depende de la versión de las bibliotecas de componentes internacionales de Unicode instaladas en el sistema.The specific version of the sort weight table on Linux and macOS depends on the version of the International Components for Unicode libraries installed on the system. Para más información sobre las versiones de los componentes internacionales de Unicode y las versiones de Unicode que implementan, vea la información sobre la descarga de componentes internacionales de Unicode.For information on ICU versions and the Unicode versions that they implement, see Downloading ICU.

Sin embargo, la evaluación de dos cadenas para comprobar su igualdad o su criterio de ordenación no produce ningún resultado correcto único; el resultado depende de los criterios empleados para comparar las cadenas.However, evaluating two strings for equality or sort order does not yield a single, correct result; the outcome depends on the criteria used to compare the strings. En especial, las comparaciones de cadenas que son ordinales o que se basan en las convenciones de ordenación y uso de mayúsculas y minúsculas de la referencia cultural actual o de la referencia cultural de todos los idiomas (una referencia cultural válida para la configuración regional basada en el idioma inglés) pueden producir resultados diferentes.In particular, string comparisons that are ordinal or that are based on the casing and sorting conventions of the current culture or the invariant culture (a locale-agnostic culture based on the English language) may produce different results.

Además, las comparaciones de cadenas mediante las diferentes versiones de .NET o con .NET en distintos sistemas operativos o versiones de sistema operativo pueden devolver resultados diferentes.In addition, string comparisons using different versions of .NET or using .NET on different operating systems or operating system versions may return different results. Para más información, vea Las cadenas y el estándar Unicode.For more information, see Strings and the Unicode Standard.

Comparaciones de cadenas que usan la referencia cultural actualString Comparisons that Use the Current Culture

Un criterio implica usar las convenciones de la referencia cultural actual a la hora de comparar cadenas.One criterion involves using the conventions of the current culture when comparing strings. Las comparaciones que se basan en la referencia cultural actual usan la referencia cultural o la configuración regional actual del subproceso.Comparisons that are based on the current culture use the thread's current culture or locale. Si el usuario no establece la referencia cultural, se usa como valor predeterminado la configuración de la ventana Opciones regionales del Panel de control.If the culture is not set by the user, it defaults to the setting in the Regional Options window in Control Panel. Siempre debe usar comparaciones basadas en la referencia cultural actual cuando los datos sean lingüísticamente pertinentes y cuando refleje una interacción con el usuario dependiente de la referencia cultural.You should always use comparisons that are based on the current culture when data is linguistically relevant, and when it reflects culture-sensitive user interaction.

En cambio, el comportamiento de comparación y uso de mayúsculas y minúsculas de .NET cambia cuando la referencia cultural cambia.However, comparison and casing behavior in .NET changes when the culture changes. Esto ocurre cuando una aplicación se ejecuta en un equipo que tiene una referencia cultural diferente que el equipo en el que se desarrolló la aplicación o cuando el subproceso en ejecución cambia su referencia cultural.This happens when an application executes on a computer that has a different culture than the computer on which the application was developed, or when the executing thread changes its culture. Este comportamiento es deliberado, pero sigue resultando no obvio para muchos desarrolladores.This behavior is intentional, but it remains non-obvious to many developers. En el ejemplo siguiente, se muestran las diferencias en el criterio de ordenación entre las referencias culturales de inglés de EE. UU. ("en-US") y sueco ("sv-SE").The following example illustrates differences in sort order between the U.S. English ("en-US") and Swedish ("sv-SE") cultures. Tenga en cuenta que las palabras "ångström", "Windows" y "Visual Studio" aparecen en distintas posiciones en las matrices de cadenas ordenadas.Note that the words "ångström", "Windows", and "Visual Studio" appear in different positions in the sorted string arrays.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      string[] values= { "able", "ångström", "apple", "Æble", 
                         "Windows", "Visual Studio" };
      Array.Sort(values);
      DisplayArray(values);

      // Change culture to Swedish (Sweden).
      string originalCulture = CultureInfo.CurrentCulture.Name;
      Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
      Array.Sort(values);
      DisplayArray(values);

      // Restore the original culture.
      Thread.CurrentThread.CurrentCulture = new CultureInfo(originalCulture);
    }
    
    private static void DisplayArray(string[] values)
    {
      Console.WriteLine("Sorting using the {0} culture:",  
                        CultureInfo.CurrentCulture.Name);
      foreach (string value in values)
         Console.WriteLine("   {0}", value);

      Console.WriteLine();
    }
}
// The example displays the following output:
//       Sorting using the en-US culture:
//          able
//          Æble
//          ångström
//          apple
//          Visual Studio
//          Windows
//       
//       Sorting using the sv-SE culture:
//          able
//          Æble
//          apple
//          Windows
//          Visual Studio
//          ångström
Imports System.Globalization
Imports System.Threading

Module Example
   Public Sub Main()
      Dim values() As String = { "able", "ångström", "apple", _
                                 "Æble", "Windows", "Visual Studio" }
      Array.Sort(values)
      DisplayArray(values)

      ' Change culture to Swedish (Sweden).
      Dim originalCulture As String = CultureInfo.CurrentCulture.Name
      Thread.CurrentThread.CurrentCulture = New CultureInfo("sv-SE")
      Array.Sort(values)
      DisplayArray(values)

      ' Restore the original culture.
      Thread.CurrentThread.CurrentCulture = New CultureInfo(originalCulture)
    End Sub
    
    Private Sub DisplayArray(values() As String)
      Console.WRiteLine("Sorting using the {0} culture:", _ 
                        CultureInfo.CurrentCulture.Name)
      For Each value As String In values
         Console.WriteLine("   {0}", value)
      Next
      Console.WriteLine()   
    End Sub
End Module
' The example displays the following output:
'       Sorting using the en-US culture:
'          able
'          Æble
'          ångström
'          apple
'          Visual Studio
'          Windows
'       
'       Sorting using the sv-SE culture:
'          able
'          Æble
'          apple
'          Windows
'          Visual Studio
'          ångström

Las comparaciones sin distinción entre mayúsculas y minúsculas que usan la referencia cultural actual son iguales que las comparaciones dependientes de la referencia cultural, excepto que omiten el uso de mayúsculas y minúsculas según indica la referencia cultural actual del subproceso.Case-insensitive comparisons that use the current culture are the same as culture-sensitive comparisons, except that they ignore case as dictated by the thread's current culture. Este comportamiento también se puede manifestar en los criterios de ordenación.This behavior may manifest itself in sort orders as well.

Las comparaciones que usan semántica de la referencia cultural actual son el valor predeterminado para los métodos siguientes:Comparisons that use current culture semantics are the default for the following methods:

En cualquier caso, se recomienda llamar a una sobrecarga que tenga un parámetro StringComparison para aclarar la intención de la llamada al método.In any case, we recommend that you call an overload that has a StringComparison parameter to make the intent of the method call clear.

Pueden surgir errores imperceptibles y no tan imperceptibles cuando los datos de cadenas no lingüísticos se interpretan lingüísticamente, o cuando los datos de cadenas de una referencia cultural determinada se interpretan usando las convenciones de otra referencia cultural.Subtle and not so subtle bugs can emerge when non-linguistic string data is interpreted linguistically, or when string data from a particular culture is interpreted using the conventions of another culture. El ejemplo canónico es el problema con I en turco.The canonical example is the Turkish-I problem.

Para casi todos los alfabetos latinos, incluso en inglés de EE. UU., el carácter "i" (\u0069) es la versión en minúsculas del carácter "I" (\u0049).For nearly all Latin alphabets, including U.S. English, the character "i" (\u0069) is the lowercase version of the character "I" (\u0049). Esta regla de mayúsculas y minúsculas se convierte rápidamente en el valor predeterminado para alguien que programe en esa referencia cultural.This casing rule quickly becomes the default for someone programming in such a culture. En cambio, el alfabeto turco ("tr-TR") incluye un carácter "I con punto" "İ" (\u0130), que es la versión en mayúsculas de "i".However, the Turkish ("tr-TR") alphabet includes an "I with a dot" character "İ" (\u0130), which is the capital version of "i". El turco también incluye un carácter "i sin punto" en minúscula, "ı" (\u0131), que en mayúsculas es "I".Turkish also includes a lowercase "i without a dot" character, "ı" (\u0131), which capitalizes to "I". Este comportamiento también se produce en la referencia cultural de azerbaiyano ("az").This behavior occurs in the Azerbaijani ("az") culture as well.

Por tanto, los supuestos sobre poner en mayúsculas "i" o escribir "I" en minúsculas no son válidas en todas las referencias culturales.Therefore, assumptions made about capitalizing "i" or lowercasing "I" are not valid among all cultures. Si usa las sobrecargas predeterminadas para las rutinas de comparación de cadenas, estarán sujetas a variaciones entre distintas referencias culturales.If you use the default overloads for string comparison routines, they will be subject to variance between cultures. Si los datos que se van a comparar son no lingüísticos, el uso de las sobrecargas predeterminadas puede generar resultados no deseables, como ilustra el siguiente intento de realizar una comparación sin distinción entre mayúsculas y minúsculas de las cadenas "file" y "FILE".If the data to be compared is non-linguistic, using the default overloads can produce undesirable results, as the following attempt to perform a case-insensitive comparison of the strings "file" and "FILE" illustrates.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      string fileUrl = "file";
      Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}", 
                       fileUrl.StartsWith("FILE", true, null));
      Console.WriteLine();
      
      Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}", 
                        fileUrl.StartsWith("FILE", true, null));
   }
}
// The example displays the following output:
//       Culture = English (United States)
//       (file == FILE) = True
//       
//       Culture = Turkish (Turkey)
//       (file == FILE) = False
Imports System.Globalization
Imports System.Threading

Module Example
   Public Sub Main()
      Dim fileUrl = "file"
      Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
      Console.WriteLine("Culture = {0}", _
                        Thread.CurrentThread.CurrentCulture.DisplayName)
      Console.WriteLine("(file == FILE) = {0}", _ 
                       fileUrl.StartsWith("FILE", True, Nothing))
      Console.WriteLine()
      
      Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")
      Console.WriteLine("Culture = {0}", _
                        Thread.CurrentThread.CurrentCulture.DisplayName)
      Console.WriteLine("(file == FILE) = {0}", _ 
                        fileUrl.StartsWith("FILE", True, Nothing))
   End Sub
End Module
' The example displays the following output:
'       Culture = English (United States)
'       (file == FILE) = True
'       
'       Culture = Turkish (Turkey)
'       (file == FILE) = False

Esta comparación podría producir problemas importantes si la referencia cultural se usa involuntariamente en configuraciones que afectan a la seguridad, como en el ejemplo siguiente.This comparison could cause significant problems if the culture is inadvertently used in security-sensitive settings, as in the following example. Una llamada al método como IsFileURI("file:") devuelve true si la referencia cultural actual es inglés de EE. U.U., pero false si la referencia cultural actual es el turco.A method call such as IsFileURI("file:") returns true if the current culture is U.S. English, but false if the current culture is Turkish. Así, en los sistemas turcos, alguien podría sortear las medidas de seguridad que bloquean el acceso a los URI sin distinción entre mayúsculas y minúsculas que comienzan con "FILE":.Thus, on Turkish systems, someone could circumvent security measures that block access to case-insensitive URIs that begin with "FILE:".

public static bool IsFileURI(String path) 
{
   return path.StartsWith("FILE:", true, null);
}
Public Shared Function IsFileURI(path As String) As Boolean 
   Return path.StartsWith("FILE:", True, Nothing)
End Function

En este caso, puesto que "file:" debe interpretarse como un identificador no lingüístico e independiente de la referencia cultural, el código se debe escribir como se muestra en el ejemplo siguiente.In this case, because "file:" is meant to be interpreted as a non-linguistic, culture-insensitive identifier, the code should instead be written as shown in the following example.

public static bool IsFileURI(string path) 
{
   return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
}
Public Shared Function IsFileURI(path As String) As Boolean 
    Return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase)
End Function

Operaciones de cadenas ordinalesOrdinal String Operations

Al especificar el valor StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase en una llamada al método, se indica una comparación no lingüística en la que se omiten las características de los lenguajes naturales.Specifying the StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase value in a method call signifies a non-linguistic comparison in which the features of natural languages are ignored. Los métodos que se invocan con estos valores StringComparison basan las decisiones sobre las operaciones con cadenas en simples comparaciones de bytes en lugar de usos de mayúsculas y minúsculas o tablas de equivalencia parametrizadas por referencia cultural.Methods that are invoked with these StringComparison values base string operation decisions on simple byte comparisons instead of casing or equivalence tables that are parameterized by culture. En la mayoría de los casos, este enfoque se adapta mejor a la interpretación prevista de cadenas, y el código es más rápido y más confiable.In most cases, this approach best fits the intended interpretation of strings while making code faster and more reliable.

Las comparaciones ordinales son comparaciones de cadenas en las que cada byte de cada cadena se compara sin ninguna interpretación lingüística; por ejemplo, "windows" no coincide con "Windows".Ordinal comparisons are string comparisons in which each byte of each string is compared without linguistic interpretation; for example, "windows" does not match "Windows". Esta es, esencialmente, una llamada a la función strcmp en tiempo de ejecución de C.This is essentially a call to the C runtime strcmp function. Use esta comparación cuando el contexto indique que las cadenas deben coincidir exactamente o exija una directiva de coincidencia conservadora.Use this comparison when the context dictates that strings should be matched exactly or demands conservative matching policy. Además, la comparación ordinal es la operación de comparación más rápida porque no aplica ninguna regla lingüística al determinar un resultado.Additionally, ordinal comparison is the fastest comparison operation because it applies no linguistic rules when determining a result.

En .NET, las cadenas pueden contener caracteres nulos incrustados.Strings in .NET can contain embedded null characters. Una de las diferencias más claras entre la comparación ordinal y dependiente de la referencia cultural (incluyendo las comparaciones que usan la referencia cultural de todos los idiomas) tiene que ver con el control de caracteres nulos incrustados en una cadena.One of the clearest differences between ordinal and culture-sensitive comparison (including comparisons that use the invariant culture) concerns the handling of embedded null characters in a string. Estos caracteres se omiten cuando usa métodos String.Compare y String.Equals para realizar comparaciones dependientes de la referencia cultural (incluyendo las comparaciones que usan la referencia cultural de todos los idiomas).These characters are ignored when you use the String.Compare and String.Equals methods to perform culture-sensitive comparisons (including comparisons that use the invariant culture). Por tanto, en las comparaciones dependientes de la referencia cultural, las cadenas que contienen caracteres nulos incrustados pueden considerarse iguales que las cadenas que no los contienen.As a result, in culture-sensitive comparisons, strings that contain embedded null characters can be considered equal to strings that do not.

Importante

Aunque los métodos de comparación de cadenas hacen caso omiso de los caracteres nulos incrustados, los métodos de búsqueda de cadenas como String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOfy String.StartsWith sí los tienen en cuenta.Although string comparison methods disregard embedded null characters, string search methods such as String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOf, and String.StartsWith do not.

En el ejemplo siguiente se realiza una comparación dependiente de la referencia cultural de la cadena "Aa" con una cadena similar que contiene varios caracteres nulos incrustados entre "A" y "a", y se muestra cómo las dos cadenas se consideran iguales.The following example performs a culture-sensitive comparison of the string "Aa" with a similar string that contains several embedded null characters between "A" and "a", and shows how the two strings are considered equal.

using System;

public class Example
{
   public static void Main()
   {
      string str1 = "Aa";
      string str2 = "A" + new String('\u0000', 3) + "a";
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", 
                        str1, ShowBytes(str1), str2, ShowBytes(str2));
      Console.WriteLine("   With String.Compare:");
      Console.WriteLine("      Current Culture: {0}", 
                        String.Compare(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}", 
                        String.Compare(str1, str2, StringComparison.InvariantCulture));

      Console.WriteLine("   With String.Equals:");
      Console.WriteLine("      Current Culture: {0}", 
                        String.Equals(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}", 
                        String.Equals(str1, str2, StringComparison.InvariantCulture));
   }
   
   private static string ShowBytes(string str)
   {
      string hexString = String.Empty;
      for (int ctr = 0; ctr < str.Length; ctr++)
      {
         string result = String.Empty;
         result = Convert.ToInt32(str[ctr]).ToString("X4");
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2);
         hexString += result;
      }
      return hexString.Trim();
   }
}
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Current Culture: 0
//          Invariant Culture: 0
//       With String.Equals:
//          Current Culture: True
//          Invariant Culture: True
Module Example
   Public Sub Main()
      Dim str1 As String = "Aa"
      Dim str2 As String = "A" + New String(Convert.ToChar(0), 3) + "a"
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
                        str1, ShowBytes(str1), str2, ShowBytes(str2))
      Console.WriteLine("   With String.Compare:")
      Console.WriteLine("      Current Culture: {0}", _
                        String.Compare(str1, str2, StringComparison.CurrentCulture))
      Console.WriteLine("      Invariant Culture: {0}", _
                        String.Compare(str1, str2, StringComparison.InvariantCulture))

      Console.WriteLine("   With String.Equals:")
      Console.WriteLine("      Current Culture: {0}", _
                        String.Equals(str1, str2, StringComparison.CurrentCulture))
      Console.WriteLine("      Invariant Culture: {0}", _
                        String.Equals(str1, str2, StringComparison.InvariantCulture))
   End Sub
   
   Private Function ShowBytes(str As String) As String
      Dim hexString As String = String.Empty
      For ctr As Integer = 0 To str.Length - 1
         Dim result As String = String.Empty
         result = Convert.ToInt32(str.Chars(ctr)).ToString("X4")
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2)
         hexString += result
      Next
      Return hexString.Trim()
   End Function
End Module

Sin embargo, las cadenas no se consideran iguales cuando usa la comparación ordinal, como se muestra en el ejemplo siguiente.However, the strings are not considered equal when you use ordinal comparison, as the following example shows.

Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", 
                  str1, ShowBytes(str1), str2, ShowBytes(str2));
Console.WriteLine("   With String.Compare:");
Console.WriteLine("      Ordinal: {0}", 
                  String.Compare(str1, str2, StringComparison.Ordinal));

Console.WriteLine("   With String.Equals:");
Console.WriteLine("      Ordinal: {0}", 
                  String.Equals(str1, str2, StringComparison.Ordinal));
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Ordinal: 97
//       With String.Equals:
//          Ordinal: False
Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
                  str1, ShowBytes(str1), str2, ShowBytes(str2))
Console.WriteLine("   With String.Compare:")
Console.WriteLine("      Ordinal: {0}", _
                  String.Compare(str1, str2, StringComparison.Ordinal))

Console.WriteLine("   With String.Equals:")
Console.WriteLine("      Ordinal: {0}", _
                  String.Equals(str1, str2, StringComparison.Ordinal))
' The example displays the following output:
'    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
'       With String.Compare:
'          Ordinal: 97
'       With String.Equals:
'          Ordinal: False

Las comparaciones ordinales sin distinción entre mayúsculas y minúsculas son el siguiente enfoque más conservador.Case-insensitive ordinal comparisons are the next most conservative approach. Estas comparaciones omiten la mayor parte del uso de mayúsculas y minúsculas; por ejemplo, "windows" coincide con "Windows".These comparisons ignore most casing; for example, "windows" matches "Windows". A la hora de tratar con caracteres ASCII, esta directiva es equivalente a StringComparison.Ordinal, salvo que omite el uso de mayúsculas y minúsculas habitual de ASCII.When dealing with ASCII characters, this policy is equivalent to StringComparison.Ordinal, except that it ignores the usual ASCII casing. Por tanto, cualquier carácter de [A, Z] (\u0041-\u005A) coincide con el carácter correspondiente de [a, z] (\u0061-\007A).Therefore, any character in [A, Z] (\u0041-\u005A) matches the corresponding character in [a,z] (\u0061-\007A). El uso de mayúsculas y minúsculas fuera del intervalo ASCII emplea las tablas de la referencia cultural de todos los idiomas.Casing outside the ASCII range uses the invariant culture's tables. Por tanto, la siguiente comparación:Therefore, the following comparison:

String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);
String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase)

es equivalente a esta comparación (pero más rápida):is equivalent to (but faster than) this comparison:

String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), 
               StringComparison.Ordinal);
String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), 
               StringComparison.Ordinal)

Estas comparaciones siguen siendo muy rápidas.These comparisons are still very fast.

Nota

El comportamiento de las cadenas del sistema de archivos, claves del Registro y valores, y variables de entorno se representa mejor mediante StringComparison.OrdinalIgnoreCase.The string behavior of the file system, registry keys and values, and environment variables is best represented by StringComparison.OrdinalIgnoreCase.

Tanto StringComparison.Ordinal como StringComparison.OrdinalIgnoreCase usan los valores binarios directamente y son más adecuados para la búsqueda de coincidencias.Both StringComparison.Ordinal and StringComparison.OrdinalIgnoreCase use the binary values directly, and are best suited for matching. Si no sabe con seguridad qué configuración de comparación debe emplear, use uno de estos dos valores.When you are not sure about your comparison settings, use one of these two values. Sin embargo, puesto que realizan una comparación byte a byte, no ordenan según un criterio de ordenación lingüístico (como un diccionario de inglés) sino según un criterio de ordenación binario.However, because they perform a byte-by-byte comparison, they do not sort by a linguistic sort order (like an English dictionary) but by a binary sort order. Los resultados pueden parecer extraños en la mayoría de los contextos si se muestran a los usuarios.The results may look odd in most contexts if displayed to users.

La semántica ordinal es el valor predeterminado para las sobrecargas de String.Equals que no incluyen un argumento StringComparison (incluyendo el operador de igualdad).Ordinal semantics are the default for String.Equals overloads that do not include a StringComparison argument (including the equality operator). En cualquier caso, se recomienda llamar a una sobrecarga que tenga un parámetro StringComparison .In any case, we recommend that you call an overload that has a StringComparison parameter.

Operaciones de cadenas que usan la referencia cultural de todos los idiomasString Operations that Use the Invariant Culture

Las comparaciones con la referencia cultural de todos los idiomas usan la propiedad CompareInfo devuelta por la propiedad estática CultureInfo.InvariantCulture.Comparisons with the invariant culture use the CompareInfo property returned by the static CultureInfo.InvariantCulture property. Este comportamiento es igual en todos los sistemas; traduce cualquier carácter que esté fuera de su intervalo en lo que cree que son caracteres invariables equivalentes.This behavior is the same on all systems; it translates any characters outside its range into what it believes are equivalent invariant characters. Esta directiva puede ser útil para mantener un conjunto de comportamientos de las cadenas en distintas referencias culturales, pero a menudo proporciona resultados inesperados.This policy can be useful for maintaining one set of string behavior across cultures, but it often provides unexpected results.

Las comparaciones sin distinción entre mayúsculas y minúsculas con la referencia cultural de todos los idiomas usan también la propiedad estática CompareInfo devuelta por la propiedad estática CultureInfo.InvariantCulture para obtener información de comparación.Case-insensitive comparisons with the invariant culture use the static CompareInfo property returned by the static CultureInfo.InvariantCulture property for comparison information as well. Cualquier diferencia en el uso de mayúsculas y minúsculas entre estos caracteres traducidos se pasa por alto.Any case differences among these translated characters are ignored.

Las comparaciones que usan StringComparison.InvariantCulture y StringComparison.Ordinal funcionan de manera idéntica en cadenas ASCII.Comparisons that use StringComparison.InvariantCulture and StringComparison.Ordinal work identically on ASCII strings. Sin embargo, StringComparison.InvariantCulture toma decisiones lingüísticas que podrían no ser adecuadas para las cadenas que tienen que interpretarse como un conjunto de bytes.However, StringComparison.InvariantCulture makes linguistic decisions that might not be appropriate for strings that have to be interpreted as a set of bytes. El objeto CultureInfo.InvariantCulture.CompareInfo hace que el método Compare interprete ciertos conjuntos de caracteres como equivalentes.The CultureInfo.InvariantCulture.CompareInfo object makes the Compare method interpret certain sets of characters as equivalent. Por ejemplo, la siguiente equivalencia es válida en la referencia cultural de todos los idiomas:For example, the following equivalence is valid under the invariant culture:

InvariantCulture: a + ̊ = åInvariantCulture: a + ̊ = å

El carácter LETRA LATINA A MINÚSCULA "a" (\u0061), cuando está junto al carácter ANILLO SUPERIOR COMBINABLE "+ " ̊" (\u030a), se interpreta como el carácter LETRA LATINA MINÚSCULA A CON ANILLO SUPERIOR "å" (\u00e5).The LATIN SMALL LETTER A character "a" (\u0061), when it is next to the COMBINING RING ABOVE character "+ " ̊" (\u030a), is interpreted as the LATIN SMALL LETTER A WITH RING ABOVE character "å" (\u00e5). Como se muestra en el ejemplo siguiente, este comportamiento difiere de la comparación ordinal.As the following example shows, this behavior differs from ordinal comparison.

string separated = "\u0061\u030a";
string combined = "\u00e5";
      
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}",
                  separated, combined, 
                  String.Compare(separated, combined, 
                                 StringComparison.InvariantCulture) == 0);

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}",
                  separated, combined,
                  String.Compare(separated, combined, 
                                 StringComparison.Ordinal) == 0);
// The example displays the following output:
//    Equal sort weight of a° and å using InvariantCulture: True
//    Equal sort weight of a° and å using Ordinal: False      
Dim separated As String = ChrW(&h61) + ChrW(&h30a)
Dim combined As String = ChrW(&he5)
      
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}", _
                  separated, combined, _
                  String.Compare(separated, combined, _ 
                                 StringComparison.InvariantCulture) = 0)

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}", _
                  separated, combined, _
                  String.Compare(separated, combined, _
                                 StringComparison.Ordinal) = 0)
' The example displays the following output:
'    Equal sort weight of a° and å using InvariantCulture: True
'    Equal sort weight of a° and å using Ordinal: False

A la hora de interpretar nombres de archivo, cookies u otros elementos donde pueda aparecer una combinación como "å", las comparaciones ordinales siguen ofreciendo el comportamiento más transparente y adecuado.When interpreting file names, cookies, or anything else where a combination such as "å" can appear, ordinal comparisons still offer the most transparent and fitting behavior.

En conjunto, la referencia cultural de todos los idiomas tiene muy pocas propiedades que la hagan útil para la comparación.On balance, the invariant culture has very few properties that make it useful for comparison. Realiza la comparación de manera lingüísticamente pertinente, lo que le impide garantizar una equivalencia simbólica completa, pero no es la opción ideal para la presentación en cualquier referencia cultural.It does comparison in a linguistically relevant manner, which prevents it from guaranteeing full symbolic equivalence, but it is not the choice for display in any culture. Una de las pocas razones para usar StringComparison.InvariantCulture con el fin de realizar una comparación es para conservar datos ordenados cuando se desea realizar una presentación idéntica transculturalmente.One of the few reasons to use StringComparison.InvariantCulture for comparison is to persist ordered data for a cross-culturally identical display. Por ejemplo, si un archivo de datos grande que contiene una lista de identificadores ordenados para su presentación acompaña una aplicación, al agregar datos a esta lista se necesitaría realizar una inserción con ordenación de estilo invariable.For example, if a large data file that contains a list of sorted identifiers for display accompanies an application, adding to this list would require an insertion with invariant-style sorting.

Volver al principioBack to top

Elegir un miembro StringComparison para la llamada al métodoChoosing a StringComparison Member for Your Method Call

En la tabla siguiente se describe la asignación del contexto de cadena semántico a un miembro de la enumeración de StringComparison .The following table outlines the mapping from semantic string context to a StringComparison enumeration member.

DatosData ComportamientoBehavior Valor de System.StringComparisonCorresponding System.StringComparison

valorvalue
Identificadores internos con distinción entre mayúsculas y minúsculas.Case-sensitive internal identifiers.

Identificadores con distinción entre mayúsculas y minúsculas en estándares como XML y HTTP.Case-sensitive identifiers in standards such as XML and HTTP.

Configuraciones relacionadas con la seguridad con distinción entre mayúsculas y minúsculas.Case-sensitive security-related settings.
Identificador no lingüístico, donde los bytes coinciden exactamente.A non-linguistic identifier, where bytes match exactly. Ordinal
Identificadores internos sin distinción entre mayúsculas y minúsculas.Case-insensitive internal identifiers.

Identificadores sin distinción entre mayúsculas y minúsculas en estándares como XML y HTTP.Case-insensitive identifiers in standards such as XML and HTTP.

Rutas de acceso a archivos.File paths.

Claves del Registro y valores.Registry keys and values.

Variables de entorno.Environment variables.

Identificadores de recursos (por ejemplo, nombres de identificadores).Resource identifiers (for example, handle names).

Configuraciones relacionadas con la seguridad sin distinción entre mayúsculas y minúsculas.Case-insensitive security-related settings.
Identificador no lingüístico, donde el uso de mayúsculas y minúsculas no es pertinente; especialmente datos almacenados en la mayoría de los servicios del sistema de Windows.A non-linguistic identifier, where case is irrelevant; especially data stored in most Windows system services. OrdinalIgnoreCase
Algunos datos almacenados lingüísticamente pertinentes.Some persisted, linguistically relevant data.

Presentación de datos lingüísticos que necesitan un criterio de ordenación fijo.Display of linguistic data that requires a fixed sort order.
Datos válidos culturalmente que siguen siendo lingüísticamente pertinentes.Culturally agnostic data that still is linguistically relevant. InvariantCulture

O bien-or-

InvariantCultureIgnoreCase
Datos mostrados al usuario.Data displayed to the user.

La mayoría de los datos proporcionados por el usuario.Most user input.
Datos que necesitan personalizaciones lingüísticas locales.Data that requires local linguistic customs. CurrentCulture

O bien-or-

CurrentCultureIgnoreCase

Volver al principioBack to top

Métodos comunes de comparación de cadenas en .NETCommon String Comparison Methods in .NET

En las secciones siguientes se describen los métodos que se usan con más frecuencia para la comparación de cadenas.The following sections describe the methods that are most commonly used for string comparison.

String.CompareString.Compare

Interpretación predeterminada: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Al ser la operación fundamental para la interpretación de cadenas, todas las instancias de estas llamadas al método se deben examinar para determinar si las cadenas se deben interpretar según la referencia cultural actual o se deben separar de la referencia cultural (simbólicamente).As the operation most central to string interpretation, all instances of these method calls should be examined to determine whether strings should be interpreted according to the current culture, or dissociated from the culture (symbolically). Normalmente, se trata del último caso y se debe usar en su lugar una comparación StringComparison.Ordinal .Typically, it is the latter, and a StringComparison.Ordinal comparison should be used instead.

La clase System.Globalization.CompareInfo, devuelta por la propiedad CultureInfo.CompareInfo, también incluye un método Compare que proporciona un gran número de opciones de coincidencia (ordinal, omitir el espacio en blanco, omitir el tipo de kana, etc.) por medio de la enumeración de marca CompareOptions.The System.Globalization.CompareInfo class, which is returned by the CultureInfo.CompareInfo property, also includes a Compare method that provides a large number of matching options (ordinal, ignoring white space, ignoring kana type, and so on) by means of the CompareOptions flag enumeration.

String.CompareToString.CompareTo

Interpretación predeterminada: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Este método no ofrece actualmente una sobrecarga que especifique un tipo StringComparison .This method does not currently offer an overload that specifies a StringComparison type. Normalmente es posible convertir este método en el formato recomendado del método String.Compare(String, String, StringComparison).It is usually possible to convert this method to the recommended String.Compare(String, String, StringComparison) form.

Los tipos que implementan interfaces IComparable y IComparable<T> implementan este método.Types that implement the IComparable and IComparable<T> interfaces implement this method. Puesto que no ofrece la opción de un parámetro StringComparison , la implementación de tipos suele permitir al usuario especificar StringComparer en su constructor.Because it does not offer the option of a StringComparison parameter, implementing types often let the user specify a StringComparer in their constructor. En el ejemplo siguiente se define una clase FileName cuyo constructor de clase incluye un parámetro StringComparer .The following example defines a FileName class whose class constructor includes a StringComparer parameter. Este objeto StringComparer se usa entonces en el método FileName.CompareTo .This StringComparer object is then used in the FileName.CompareTo method.

using System;

public class FileName : IComparable
{
   string fname;
   StringComparer comparer; 
   
   public FileName(string name, StringComparer comparer)
   {
      if (String.IsNullOrEmpty(name))
         throw new ArgumentNullException("name");

      this.fname = name;
      
      if (comparer != null)
         this.comparer = comparer;
      else
         this.comparer = StringComparer.OrdinalIgnoreCase;
   }

   public string Name
   {
      get { return fname; }
   }
   
   public int CompareTo(object obj)
   {
      if (obj == null) return 1;

      if (! (obj is FileName))
         return comparer.Compare(this.fname, obj.ToString());
      else
         return comparer.Compare(this.fname, ((FileName) obj).Name);
   }
}
Public Class FileName : Implements IComparable
   Dim fname As String
   Dim comparer As StringComparer 
   
   Public Sub New(name As String, comparer As StringComparer)
      If String.IsNullOrEmpty(name) Then
         Throw New ArgumentNullException("name")
      End If

      Me.fname = name
      
      If comparer IsNot Nothing Then
         Me.comparer = comparer
      Else
         Me.comparer = StringComparer.OrdinalIgnoreCase
      End If      
   End Sub

   Public ReadOnly Property Name As String
      Get
         Return fname
      End Get   
   End Property
   
   Public Function CompareTo(obj As Object) As Integer _
          Implements IComparable.CompareTo
      If obj Is Nothing Then Return 1

      If Not TypeOf obj Is FileName Then
         obj = obj.ToString()
      Else
         obj = CType(obj, FileName).Name
      End If         
      Return comparer.Compare(Me.fname, obj)
   End Function
End Class

String.EqualsString.Equals

Interpretación predeterminada: StringComparison.Ordinal.Default interpretation: StringComparison.Ordinal.

La clase String le permite comprobar la igualdad llamando a las sobrecargas de método estático o de instancia Equals , o usando el operador de igualdad estático.The String class lets you test for equality by calling either the static or instance Equals method overloads, or by using the static equality operator. Las sobrecargas y el operador usan la comparación ordinal de forma predeterminada.The overloads and operator use ordinal comparison by default. Sin embargo, todavía sigue siendo recomendable llamar a una sobrecarga que especifique explícitamente el tipo StringComparison aunque desee realizar una comparación ordinal; esto facilita la búsqueda de cierta interpretación de la cadena en el código.However, we still recommend that you call an overload that explicitly specifies the StringComparison type even if you want to perform an ordinal comparison; this makes it easier to search code for a certain string interpretation.

String.ToUpper y String.ToLowerString.ToUpper and String.ToLower

Interpretación predeterminada: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Debe tener cuidado al usar estos métodos, ya que forzar que una cadena esté en mayúsculas o en minúsculas se usa a menudo como una pequeña normalización para comparar cadenas independientemente del uso de mayúsculas y minúsculas.You should be careful when you use these methods, because forcing a string to a uppercase or lowercase is often used as a small normalization for comparing strings regardless of case. En tal caso, considere la posibilidad de emplear una comparación sin distinción entre mayúsculas y minúsculas.If so, consider using a case-insensitive comparison.

También están disponibles los métodos String.ToUpperInvariant y String.ToLowerInvariant.The String.ToUpperInvariant and String.ToLowerInvariant methods are also available. ToUpperInvariant es la manera estándar de normalizar el uso de mayúsculas y minúsculas.ToUpperInvariant is the standard way to normalize case. Las comparaciones realizadas mediante StringComparison.OrdinalIgnoreCase tienen un comportamiento que es la composición de dos llamadas: llamar a ToUpperInvariant en ambos argumentos de cadena y realizar una comparación mediante StringComparison.Ordinal.Comparisons made using StringComparison.OrdinalIgnoreCase are behaviorally the composition of two calls: calling ToUpperInvariant on both string arguments, and doing a comparison using StringComparison.Ordinal.

También hay sobrecargas para convertir a mayúsculas y minúsculas en una referencia cultural concreta, pasando al método un objeto CultureInfo que representa esa referencia cultural.Overloads are also available for converting to uppercase and lowercase in a specific culture, by passing a CultureInfo object that represents that culture to the method.

Char.ToUpper y Char.ToLowerChar.ToUpper and Char.ToLower

Interpretación predeterminada: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Estos métodos funcionan de manera similar a los métodos String.ToUpper y String.ToLower descritos en la sección anterior.These methods work similarly to the String.ToUpper and String.ToLower methods described in the previous section.

String.StartsWith y String.EndsWithString.StartsWith and String.EndsWith

Interpretación predeterminada: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

De forma predeterminada, estos dos métodos realizan una comparación dependiente de la referencia cultural.By default, both of these methods perform a culture-sensitive comparison.

String.IndexOf y String.LastIndexOfString.IndexOf and String.LastIndexOf

Interpretación predeterminada: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

No hay coherencia en cómo las sobrecargas predeterminadas de estos métodos realizan las comparaciones.There is a lack of consistency in how the default overloads of these methods perform comparisons. Todos los métodos String.IndexOf y String.LastIndexOf que incluyen un parámetro Char realizan una comparación ordinal, pero los métodos String.IndexOf y String.LastIndexOf predeterminados que incluyen un parámetro String realizan una comparación dependiente de la referencia cultural.All String.IndexOf and String.LastIndexOf methods that include a Char parameter perform an ordinal comparison, but the default String.IndexOf and String.LastIndexOf methods that include a String parameter perform a culture-sensitive comparison.

Si llama al método String.IndexOf(String) o String.LastIndexOf(String) y le pasa una cadena para ubicar en la instancia actual, se recomienda llamar a una sobrecarga que especifique explícitamente el tipo StringComparison .If you call the String.IndexOf(String) or String.LastIndexOf(String) method and pass it a string to locate in the current instance, we recommend that you call an overload that explicitly specifies the StringComparison type. Las sobrecargas que incluyen un argumento Char no le permiten especificar un tipo StringComparison .The overloads that include a Char argument do not allow you to specify a StringComparison type.

Volver al principioBack to top

Métodos que realizan la comparación de cadenas indirectamenteMethods that Perform String Comparison Indirectly

Algunos métodos sin cadenas que tienen la comparación de cadenas como operación fundamental usan el tipo StringComparer .Some non-string methods that have string comparison as a central operation use the StringComparer type. La clase StringComparer incluye seis propiedades estáticas que devuelven instancias de StringComparer cuyos métodos StringComparer.Compare realizan los siguientes tipos de comparaciones de cadenas:The StringComparer class includes six static properties that return StringComparer instances whose StringComparer.Compare methods perform the following types of string comparisons:

Array.Sort y Array.BinarySearchArray.Sort and Array.BinarySearch

Interpretación predeterminada: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

Cuando se almacenan datos en una colección, o cuando se leen datos almacenados de un archivo o una base de datos en una colección, el cambio de la referencia cultural actual puede invalidar los valores invariables de la colección.When you store any data in a collection, or read persisted data from a file or database into a collection, switching the current culture can invalidate the invariants in the collection. El método Array.BinarySearch supone que los elementos de la matriz que se van a buscar ya están ordenados.The Array.BinarySearch method assumes that the elements in the array to be searched are already sorted. Para ordenar cualquier elemento de cadena de la matriz, el método Array.Sort llama al método String.Compare para ordenar los elementos individuales.To sort any string element in the array, the Array.Sort method calls the String.Compare method to order individual elements. El uso de un comparador dependiente de la referencia cultural puede ser peligroso si la referencia cultural cambia desde que se ordena la matriz hasta que se busca en su contenido.Using a culture-sensitive comparer can be dangerous if the culture changes between the time that the array is sorted and its contents are searched. Por ejemplo, en el código siguiente, el almacenamiento y la recuperación funcionan en el comparador que la propiedad Thread.CurrentThread.CurrentCulture .For example, in the following code, storage and retrieval operate on the comparer that is provided implicitly by the Thread.CurrentThread.CurrentCulture property. Si la referencia cultural puede cambiar entre las llamadas a StoreNames y DoesNameExist, y especialmente si el contenido de la matriz se conserva en alguna parte entre las dos llamadas al método, se puede producir un error en la búsqueda binaria.If the culture can change between the calls to StoreNames and DoesNameExist, and especially if the array contents are persisted somewhere between the two method calls, the binary search may fail.

// Incorrect.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names); // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name) >= 0);  // Line B.
}
' Incorrect.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names)          ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name) >= 0      ' Line B.
End Function

Aparece una variación recomendada en el ejemplo siguiente, que usa el mismo método de comparación ordinal (independiente de la referencia cultural) para ordenar y buscar en la matriz.A recommended variation appears in the following example, which uses the same ordinal (culture-insensitive) comparison method both to sort and to search the array. El código cambiado se refleja en las líneas etiquetadas como Line A y Line B en los dos ejemplos.The change code is reflected in the lines labeled Line A and Line B in the two examples.

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.Ordinal);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.Ordinal) >= 0);  // Line B.
}
' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names, StringComparer.Ordinal)           ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name, StringComparer.Ordinal) >= 0      ' Line B.
End Function

Si estos datos se conservan y mueven entre distintas referencias culturales, y se usa la ordenación para presentar estos datos al usuario, es mejor usar StringComparison.InvariantCulture, que funciona lingüísticamente para obtener una mejor salida para el usuario pero no se ve afectado por los cambios en la referencia cultural.If this data is persisted and moved across cultures, and sorting is used to present this data to the user, you might consider using StringComparison.InvariantCulture, which operates linguistically for better user output but is unaffected by changes in culture. En el ejemplo siguiente se modifican los dos ejemplos anteriores para usar la referencia cultural de todos los idiomas con el fin de ordenar y buscar en la matriz.The following example modifies the two previous examples to use the invariant culture for sorting and searching the array.

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.InvariantCulture);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.InvariantCulture) >= 0);  // Line B.
}
' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names, StringComparer.InvariantCulture)           ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name, StringComparer.InvariantCulture) >= 0      ' Line B.
End Function

Ejemplo de colecciones: constructor de tabla hashCollections Example: Hashtable Constructor

Al aplicar un algoritmo hash a las cadenas se proporciona un segundo ejemplo de una operación que se ve afectada por la forma en que se comparan las cadenas.Hashing strings provides a second example of an operation that is affected by the way in which strings are compared.

En el ejemplo siguiente se crea una instancia de un objeto Hashtable pasándole el objeto StringComparer devuelto por la propiedad StringComparer.OrdinalIgnoreCase.The following example instantiates a Hashtable object by passing it the StringComparer object that is returned by the StringComparer.OrdinalIgnoreCase property. Puesto que una clase StringComparer que se deriva de StringComparer implementa la interfaz IEqualityComparer , su método GetHashCode se usa para calcular el código hash de cadenas de la tabla hash.Because a class StringComparer that is derived from StringComparer implements the IEqualityComparer interface, its GetHashCode method is used to compute the hash code of strings in the hash table.

const int initialTableCapacity = 100;
Hashtable h;

public void PopulateFileTable(string directory)
{
   h = new Hashtable(initialTableCapacity, 
                     StringComparer.OrdinalIgnoreCase);
         
   foreach (string file in Directory.GetFiles(directory))
         h.Add(file, File.GetCreationTime(file));
}

public void PrintCreationTime(string targetFile)
{
   Object dt = h[targetFile];
   if (dt != null)
   {
      Console.WriteLine("File {0} was created at time {1}.",
         targetFile, 
         (DateTime) dt);
   }
   else
   {
      Console.WriteLine("File {0} does not exist.", targetFile);
   }
}
Const initialTableCapacity As Integer = 100
Dim h As Hashtable

Public Sub PopulateFileTable(dir As String)
   h = New Hashtable(initialTableCapacity, _
                     StringComparer.OrdinalIgnoreCase)
                     
   For Each filename As String In Directory.GetFiles(dir)
      h.Add(filename, File.GetCreationTime(filename))
   Next                        
End Sub

Public Sub PrintCreationTime(targetFile As String)
   Dim dt As Object = h(targetFile)
   If dt IsNot Nothing Then
      Console.WriteLine("File {0} was created at {1}.", _
         targetFile, _
         CDate(dt))
   Else
      Console.WriteLine("File {0} does not exist.", targetFile)
   End If
End Sub  

Volver al principioBack to top

Mostrar y conservar datos con formatoDisplaying and Persisting Formatted Data

Cuando muestre a los usuarios datos que no sean de cadena, como números, y fechas y horas, asígneles formato mediante la configuración de la referencia cultural del usuario.When you display non-string data such as numbers and dates and times to users, format them by using the user's cultural settings. De forma predeterminada, el método String.Format y los métodos ToString de los tipos numéricos y los tipos de fecha y hora usan la referencia cultural del subproceso actual para las operaciones de formato.By default, the String.Format method and the ToString methods of the numeric types and the date and time types use the current thread culture for formatting operations. Para especificar explícitamente que el método de formato debe usar la referencia cultural actual, puede llamar a una sobrecarga de un método de formato que tenga un parámetro provider , como String.Format(IFormatProvider, String, Object[]) o DateTime.ToString(IFormatProvider), y pasarle la propiedad CultureInfo.CurrentCulture .To explicitly specify that the formatting method should use the current culture, you can call an overload of a formatting method that has a provider parameter, such as String.Format(IFormatProvider, String, Object[]) or DateTime.ToString(IFormatProvider), and pass it the CultureInfo.CurrentCulture property.

Puede conservar datos que no son de cadena como datos binarios o como datos con formato.You can persist non-string data either as binary data or as formatted data. Si decide guardarlos como datos con formato, debe llamar a una sobrecarga del método de formato que incluya un parámetro provider y pasarle la propiedad CultureInfo.InvariantCulture.If you choose to save it as formatted data, you should call a formatting method overload that includes a provider parameter and pass it the CultureInfo.InvariantCulture property. La referencia cultural de todos los idiomas proporciona un formato coherente para los datos con formato que es independiente de la referencia cultural y del equipo.The invariant culture provides a consistent format for formatted data that is independent of culture and machine. En cambio, si se conservan datos a los que se aplica formato con referencias culturales distintas de la referencia cultural de todos los idiomas, se presentan varias limitaciones:In contrast, persisting data that is formatted by using cultures other than the invariant culture has a number of limitations:

  • Es probable que los datos no puedan usarse si se recuperan en un sistema que tiene una referencia cultural distinta, o si el usuario del sistema actual cambia la referencia cultural actual e intenta recuperar los datos.The data is likely to be unusable if it is retrieved on a system that has a different culture, or if the user of the current system changes the current culture and tries to retrieve the data.

  • Las propiedades de una referencia cultural en un equipo específico pueden diferir de los valores estándar.The properties of a culture on a specific computer can differ from standard values. En cualquier momento, un usuario puede personalizar la configuración de visualización que depende de la cultural.At any time, a user can customize culture-sensitive display settings. Debido a esto, es posible que los datos con formato que se guardan en un sistema no sean legibles después de que el usuario personalice la configuración de la referencia cultural.Because of this, formatted data that is saved on a system may not be readable after the user customizes cultural settings. Es posible que la portabilidad de los datos con formato entre equipos sea incluso más limitada.The portability of formatted data across computers is likely to be even more limited.

  • Las normas internacionales, regionales o nacionales que rigen el formato de los números o las fechas y horas cambian con el tiempo, y estos cambios se incorporan en las actualizaciones de los sistemas operativos Windows.International, regional, or national standards that govern the formatting of numbers or dates and times change over time, and these changes are incorporated into Windows operating system updates. Cuando cambian las convenciones de formato, los datos a los que se aplicó formato usando las convenciones anteriores pueden llegar a ser ilegibles.When formatting conventions change, data that was formatted by using the previous conventions may become unreadable.

En el ejemplo siguiente se muestra la portabilidad limitada que se deriva de usar el formato dependiente de la referencia cultural para conservar los datos.The following example illustrates the limited portability that results from using culture-sensitive formatting to persist data. En el ejemplo se guarda una matriz de valores de fecha y hora en un archivo.The example saves an array of date and time values to a file. Se les da formato con las convenciones de la referencia cultural Inglés (Estados Unidos).These are formatted by using the conventions of the English (United States) culture. Después de que la aplicación cambie la referencia cultural del subproceso actual a Francés (Suiza), intenta leer los valores guardados usando las convenciones de formato de la referencia cultural actual.After the application changes the current thread culture to French (Switzerland), it tries to read the saved values by using the formatting conventions of the current culture. El intento de leer dos de los elementos de datos genera una excepción FormatException y la matriz de fechas ahora contiene dos elementos incorrectos que iguales a MinValue.The attempt to read two of the data items throws a FormatException exception, and the array of dates now contains two incorrect elements that are equal to MinValue.

using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;

public class Example
{
   private static string filename = @".\dates.dat";

   public static void Main()
   {
      DateTime[] dates = { new DateTime(1758, 5, 6, 21, 26, 0), 
                           new DateTime(1818, 5, 5, 7, 19, 0), 
                           new DateTime(1870, 4, 22, 23, 54, 0),  
                           new DateTime(1890, 9, 8, 6, 47, 0), 
                           new DateTime(1905, 2, 18, 15, 12, 0) }; 
      // Write the data to a file using the current culture.
      WriteData(dates);
      // Change the current culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH");
      // Read the data using the current culture.
      DateTime[] newDates = ReadData();
      foreach (var newDate in newDates)
         Console.WriteLine(newDate.ToString("g"));
   }
   
   private static void WriteData(DateTime[] dates) 
   {
      StreamWriter sw = new StreamWriter(filename, false, Encoding.UTF8);    
      for (int ctr = 0; ctr < dates.Length; ctr++) {
         sw.Write("{0}", dates[ctr].ToString("g", CultureInfo.CurrentCulture));
         if (ctr < dates.Length - 1) sw.Write("|");   
      }      
      sw.Close();
   }
   
   private static DateTime[] ReadData() 
   {
      bool exceptionOccurred = false;
           
      // Read file contents as a single string, then split it.
      StreamReader sr = new StreamReader(filename, Encoding.UTF8);
      string output = sr.ReadToEnd();
      sr.Close();   

      string[] values = output.Split( new char[] { '|' } );
      DateTime[] newDates = new DateTime[values.Length]; 
      for (int ctr = 0; ctr < values.Length; ctr++) {
         try {
            newDates[ctr] = DateTime.Parse(values[ctr], CultureInfo.CurrentCulture);
         }
         catch (FormatException) {
            Console.WriteLine("Failed to parse {0}", values[ctr]);
            exceptionOccurred = true;
         }
      }      
      if (exceptionOccurred) Console.WriteLine();
      return newDates;
   }
}
// The example displays the following output:
//       Failed to parse 4/22/1870 11:54 PM
//       Failed to parse 2/18/1905 3:12 PM
//       
//       05.06.1758 21:26
//       05.05.1818 07:19
//       01.01.0001 00:00
//       09.08.1890 06:47
//       01.01.0001 00:00
//       01.01.0001 00:00
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Threading

Module Example
   Private filename As String = ".\dates.dat"
   
   Public Sub Main()
      Dim dates() As Date = { #5/6/1758 9:26PM#, #5/5/1818 7:19AM#, _ 
                              #4/22/1870 11:54PM#, #9/8/1890 6:47AM#, _ 
                              #2/18/1905 3:12PM# }
      ' Write the data to a file using the current culture.
      WriteData(dates)
      ' Change the current culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH")
      ' Read the data using the current culture.
      Dim newDates() As Date = ReadData()
      For Each newDate In newDates
         Console.WriteLine(newDate.ToString("g"))
      Next
   End Sub
   
   Private Sub WriteData(dates() As Date)
      Dim sw As New StreamWriter(filename, False, Encoding.Utf8)    
      For ctr As Integer = 0 To dates.Length - 1
         sw.Write("{0}", dates(ctr).ToString("g", CultureInfo.CurrentCulture))
         If ctr < dates.Length - 1 Then sw.Write("|")   
      Next      
      sw.Close()
   End Sub
   
   Private Function ReadData() As Date()
      Dim exceptionOccurred As Boolean = False
           
      ' Read file contents as a single string, then split it.
      Dim sr As New StreamReader(filename, Encoding.Utf8)
      Dim output As String = sr.ReadToEnd()
      sr.Close()   

      Dim values() As String = output.Split( {"|"c } )
      Dim newDates(values.Length - 1) As Date 
      For ctr As Integer = 0 To values.Length - 1
         Try
            newDates(ctr) = DateTime.Parse(values(ctr), CultureInfo.CurrentCulture)
         Catch e As FormatException
            Console.WriteLine("Failed to parse {0}", values(ctr))
            exceptionOccurred = True
         End Try
      Next      
      If exceptionOccurred Then Console.WriteLine()
      Return newDates
   End Function
End Module
' The example displays the following output:
'       Failed to parse 4/22/1870 11:54 PM
'       Failed to parse 2/18/1905 3:12 PM
'       
'       05.06.1758 21:26
'       05.05.1818 07:19
'       01.01.0001 00:00
'       09.08.1890 06:47
'       01.01.0001 00:00
'       01.01.0001 00:00
'

Sin embargo, si reemplaza la propiedad CultureInfo.CurrentCulture por CultureInfo.InvariantCulture en las llamadas a DateTime.ToString(String, IFormatProvider) y a DateTime.Parse(String, IFormatProvider), los datos persistentes de fecha y hora se restauran correctamente, como muestra el resultado siguiente.However, if you replace the CultureInfo.CurrentCulture property with CultureInfo.InvariantCulture in the calls to DateTime.ToString(String, IFormatProvider) and DateTime.Parse(String, IFormatProvider), the persisted date and time data is successfully restored, as the following output shows.

06.05.1758 21:26  
05.05.1818 07:19  
22.04.1870 23:54  
08.09.1890 06:47  
18.02.1905 15:12  

Vea tambiénSee also