Cómo comparar cadenas en C#How to compare strings in C#

Se comparan cadenas para responder a una de estas dos preguntas: "¿Son iguales estas dos cadenas?"You compare strings to answer one of two questions: "Are these two strings equal?" o "¿En qué orden deben colocarse estas cadenas al ordenarlas?"or "In what order should these strings be placed when sorting them?"

Esas dos preguntas se complican por factores que influyen en las comparaciones de cadenas:Those two questions are complicated by factors that affect string comparisons:

  • Puede elegir una comparación ordinal o lingüística.You can choose an ordinal or linguistic comparison.
  • Puede elegir si distingue entre mayúsculas y minúsculas.You can choose if case matters.
  • Puede elegir comparaciones específicas de referencia cultural.You can choose culture-specific comparisons.
  • Las comparaciones lingüísticas dependen de la plataforma y la referencia cultural.Linguistic comparisons are culture and platform-dependent.

Nota

Los ejemplos de C# de este artículo se ejecutan en el ejecutor de código en línea y área de juegos de Try.NET.The C# examples in this article run in the Try.NET inline code runner and playground. Haga clic en el botón Ejecutar para ejecutar un ejemplo en una ventana interactiva.Select the Run button to run an example in an interactive window. Una vez que se ejecuta el código, puede modificar y ejecutar el código modificado si vuelve a hacer clic en Ejecutar.Once you execute the code, you can modify it and run the modified code by selecting Run again. El código modificado se ejecuta en la ventana interactiva o, si se produce un error en la compilación, en la ventana interactiva se muestran todos los mensajes de error del compilador de C#.The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C# compiler error messages.

Cuando se comparan cadenas, se define un orden entre ellas.When you compare strings, you define an order among them. Las comparaciones se usan para ordenar una secuencia de cadenas.Comparisons are used to sort a sequence of strings. Una vez que la secuencia está en un orden conocido, es más fácil hacer búsquedas, tanto para el software como para las personas.Once the sequence is in a known order, it is easier to search, both for software and for humans. Otras comparaciones pueden comprobar si las cadenas son iguales.Other comparisons may check if strings are the same. Estas comprobaciones de similitud son parecidas a la igualdad, pero pueden omitirse algunas diferencias, como las diferencias entre mayúsculas y minúsculas.These sameness checks are similar to equality, but some differences, such as case differences, may be ignored.

Comparaciones de ordinales predeterminadasDefault ordinal comparisons

Las operaciones más habituales:The most common operations:

usan una comparación ordinal, una comparación con distinción entre mayúsculas y minúsculas y la referencia cultural actual.use an ordinal comparison, a case-sensitive comparison, and use the current culture. Los resultados se muestran en el ejemplo siguiente:The results are shown in the following example:

string root = @"C:\users";
string root2 = @"C:\Users";

bool result = root.Equals(root2);
Console.WriteLine($"Ordinal comparison: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");

result = root.Equals(root2, StringComparison.Ordinal);
Console.WriteLine($"Ordinal comparison: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");

Console.WriteLine($"Using == says that <{root}> and <{root2}> are {(root == root2 ? "equal" : "not equal")}");               

La comparación de ordinales predeterminada no tiene en cuenta reglas lingüísticas cuando se comparan cadenas.The default ordinal comparison does not take linguistic rules into account when comparing strings. Compara el valor binario de cada objeto Char en dos cadenas.It compares the binary value of each Char object in two strings. Como resultado, la comparación de ordinales predeterminada también distingue mayúsculas de minúsculas.As a result, the default ordinal comparison is also case-sensitive.

Tenga en cuenta que la prueba de igualdad con String.Equals y String.Equality es diferente de la comparación de cadenas que usa los métodos String.CompareTo y Compare(String, String).Note that the test for equality with String.Equals and String.Equality differs from string comparison using the String.CompareTo and Compare(String, String) methods. Mientras que las pruebas de igualdad realizan una comparación ordinal que distingue mayúsculas de minúsculas, el método de comparación realiza una comparación que distingue mayúsculas de minúsculas y entre referencias culturales usando la referencia cultural actual.While the tests for equality perform a case-sensitive ordinal comparison, the comparison method perform a case-sensitive, culture-sensitive comparison using the current culture. Puesto que los métodos de comparación predeterminados suelen realizan diferentes tipos de comparaciones, le recomendamos que especifique claramente la intención de su código llamando a una sobrecarga que especifique explícitamente el tipo de comparación que se realizará.Because the default comparison methods often perform different types of comparisons, we recommend that you always make the intent of your code clear by calling an overload that explicitly specifies the type of comparison to perform.

Comparaciones de ordinales sin distinción entre mayúsculas y minúsculasCase-insensitive ordinal comparisons

El método String.Equals(String, StringComparison) le permite especificar un valor StringComparison de StringComparison.OrdinalIgnoreCaseThe String.Equals(String, StringComparison) method enables you to specify a StringComparison value of StringComparison.OrdinalIgnoreCase para una comparación ordinal sin distinción entre mayúsculas y minúsculas.for a case-insensitive ordinal comparison. También hay un método String.Compare(String, String, StringComparison) estático que realiza una comparación ordinal que distingue mayúsculas de minúsculas. Para usarlo, debe especificar un valor de StringComparison.OrdinalIgnoreCase para el argumento StringComparison.There is also a static String.Compare(String, String, StringComparison) method that performs a case-insensitive ordinal comparison if you specify a value of StringComparison.OrdinalIgnoreCase for the StringComparison argument. Se muestran en este código:These are shown in the following code:

string root = @"C:\users";
string root2 = @"C:\Users";

bool result = root.Equals(root2, StringComparison.OrdinalIgnoreCase);
bool areEqual = String.Equals(root, root2, StringComparison.OrdinalIgnoreCase);
int comparison = String.Compare(root, root2, comparisonType: StringComparison.OrdinalIgnoreCase);

Console.WriteLine($"Ordinal ignore case: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");
Console.WriteLine($"Ordinal static ignore case: <{root}> and <{root2}> are {(areEqual ? "equal." : "not equal.")}");
if (comparison < 0)
    Console.WriteLine($"<{root}> is less than <{root2}>");
else if (comparison > 0)
    Console.WriteLine($"<{root}> is greater than <{root2}>");
else
    Console.WriteLine($"<{root}> and <{root2}> are equivalent in order");

Al realizar una comparación ordinal que distingue mayúsculas de minúsculas, estos métodos usarán las convenciones de mayúsculas y minúsculas de la referencia cultural invariable.When performing a case-insensitive ordinal comparison, these methods use the casing conventions of the invariant culture.

Comparaciones lingüísticasLinguistic comparisons

También se pueden ordenar cadenas mediante reglas lingüísticas para la referencia cultural actual.Strings can also be ordered using linguistic rules for the current culture. Esto se conoce a veces como "criterio de ordenación por palabras".This is sometimes referred to as "word sort order." Cuando se realiza una comparación lingüística, algunos caracteres Unicode no alfanuméricos pueden tener asignados pesos especiales.When you perform a linguistic comparison, some nonalphanumeric Unicode characters might have special weights assigned. Por ejemplo, el guion ("-") podría tener asignado un peso muy pequeño, por lo que las cadenas "coop" y "co-op" aparecerían una junto a la otra en una ordenación.For example, the hyphen "-" may have a very small weight assigned to it so that "co-op" and "coop" appear next to each other in sort order. Además, algunos caracteres Unicode pueden ser equivalentes a una secuencia de instancias de Char.In addition, some Unicode characters may be equivalent to a sequence of Char instances. En este ejemplo se usa una frase en alemán que significa "Bailan en la calle",The following example uses the phrase "They dance in the street." en alemán, con "ss" (U+0073 U+0073) en una cadena y "ß" (U+00DF) en otra.in German with the "ss" (U+0073 U+0073) in one string and 'ß' (U+00DF) in another. Lingüísticamente (en Windows), "ss" es igual que el carácter "ß" en alemán en las referencias culturales "en-US" y "de-DE".Linguistically (in Windows), "ss" is equal to the German Esszet: 'ß' character in both the "en-US" and "de-DE" cultures.

string first = "Sie tanzen auf der Straße.";
string second = "Sie tanzen auf der Strasse.";

Console.WriteLine($"First sentence is <{first}>");
Console.WriteLine($"Second sentence is <{second}>");

bool equal = String.Equals(first, second, StringComparison.InvariantCulture);
Console.WriteLine($"The two strings {(equal == true ? "are" : "are not")} equal.");
showComparison(first, second);

string word = "coop";
string words = "co-op";
string other = "cop";

showComparison(word, words);
showComparison(word, other);
showComparison(words, other);
void showComparison(string one, string two)
{
    int compareLinguistic = String.Compare(one, two, StringComparison.InvariantCulture);
    int compareOrdinal = String.Compare(one, two, StringComparison.Ordinal);
    if (compareLinguistic < 0)
        Console.WriteLine($"<{one}> is less than <{two}> using invariant culture");
    else if (compareLinguistic > 0)
        Console.WriteLine($"<{one}> is greater than <{two}> using invariant culture");
    else
        Console.WriteLine($"<{one}> and <{two}> are equivalent in order using invariant culture");
    if (compareOrdinal < 0)
        Console.WriteLine($"<{one}> is less than <{two}> using ordinal comparison");
    else if (compareOrdinal > 0)
        Console.WriteLine($"<{one}> is greater than <{two}> using ordinal comparison");
    else
        Console.WriteLine($"<{one}> and <{two}> are equivalent in order using ordinal comparison");
}

Este ejemplo demuestra la naturaleza dependiente del sistema operativo de las comparaciones lingüísticas.This sample demonstrates the operating system-dependent nature of linguistic comparisons. El host de la ventana interactiva es un host Linux.The host for the interactive window is a Linux host. Las comparaciones lingüísticas y ordinales producen el mismo resultado.The linguistic and ordinal comparisons produce the same results. Si se ejecutara este mismo ejemplo en un host de Windows, vería este resultado:If you ran this same sample on a Windows host, you would see the following output:

<coop> is less than <co-op> using invariant culture
<coop> is greater than <co-op> using ordinal comparison
<coop> is less than <cop> using invariant culture
<coop> is less than <cop> using ordinal comparison
<co-op> is less than <cop> using invariant culture
<co-op> is less than <cop> using ordinal comparison

En Windows, el criterio de ordenación de "cop", "coop" y "co-op" cambia al cambiar de una comparación lingüística a una comparación ordinal.On Windows, the sort order of "cop", "coop", and "co-op" change when you change from a linguistic comparison to an ordinal comparison. Las dos frases en alemán también se comparan de manera diferente mediante tipos de comparación diferentes.The two German sentences also compare differently using the different comparison types.

Comparaciones con referencias culturales específicasComparisons using specific cultures

En esta muestra se almacenan los objetos CultureInfo de las referencias culturales en-US y de-DE.This sample stores CultureInfo objects for the en-US and de-DE cultures. Las comparaciones se realizan con el objeto CultureInfo para garantizar una comparación específica de la referencia cultural.The comparisons are performed using a CultureInfo object to ensure a culture-specific comparison.

La referencia cultural usada afecta a las comparaciones lingüísticas.The culture used affects linguistic comparisons. En este ejemplo se muestra el resultado de comparar las dos frases en alemán usando la referencia cultural "en-US" y la referencia cultural "de-DE":The following example shows the results of comparing the two German sentences using the "en-US" culture and the "de-DE" culture:

string first = "Sie tanzen auf der Straße.";
string second = "Sie tanzen auf der Strasse.";

Console.WriteLine($"First sentence is <{first}>");
Console.WriteLine($"Second sentence is <{second}>");

var en = new System.Globalization.CultureInfo("en-US");

// For culture-sensitive comparisons, use the String.Compare 
// overload that takes a StringComparison value.
int i = String.Compare(first, second, en, System.Globalization.CompareOptions.None);
Console.WriteLine($"Comparing in {en.Name} returns {i}.");

var de = new System.Globalization.CultureInfo("de-DE");
i = String.Compare(first, second, de, System.Globalization.CompareOptions.None);
Console.WriteLine($"Comparing in {de.Name} returns {i}.");

bool b = String.Equals(first, second, StringComparison.CurrentCulture);
Console.WriteLine($"The two strings {(b ? "are" : "are not")} equal.");

string word = "coop";
string words = "co-op";
string other = "cop";

showComparison(word, words, en);
showComparison(word, other, en);
showComparison(words, other, en);
void showComparison(string one, string two, System.Globalization.CultureInfo culture)
{
    int compareLinguistic = String.Compare(one, two, en, System.Globalization.CompareOptions.None);
    int compareOrdinal = String.Compare(one, two, StringComparison.Ordinal);
    if (compareLinguistic < 0)
        Console.WriteLine($"<{one}> is less than <{two}> using en-US culture");
    else if (compareLinguistic > 0)
        Console.WriteLine($"<{one}> is greater than <{two}> using en-US culture");
    else
        Console.WriteLine($"<{one}> and <{two}> are equivalent in order using en-US culture");
    if (compareOrdinal < 0)
        Console.WriteLine($"<{one}> is less than <{two}> using ordinal comparison");
    else if (compareOrdinal > 0)
        Console.WriteLine($"<{one}> is greater than <{two}> using ordinal comparison");
    else
        Console.WriteLine($"<{one}> and <{two}> are equivalent in order using ordinal comparison");
}

Las comparaciones dependientes de la referencia cultural se usan normalmente para comparar y ordenar cadenas escritas por usuarios con otras cadenas escritas por usuarios.Culture-sensitive comparisons are typically used to compare and sort strings input by users with other strings input by users. Los caracteres y las convenciones de ordenación de estas cadenas pueden variar según la configuración regional del equipo del usuario.The characters and sorting conventions of these strings might vary depending on the locale of the user's computer. Incluso las cadenas que contienen caracteres idénticos podrían ordenarse de forma diferente en función de la referencia cultural del subproceso actual.Even strings that contain identical characters might sort differently depending on the culture of the current thread. Además, pruebe este código de ejemplo localmente en una máquina con Windows y obtendrá estos resultados:In addition, try this sample code locally on a Windows machine, and you will the following results:

<coop> is less than <co-op> using en-US culture
<coop> is greater than <co-op> using ordinal comparison
<coop> is less than <cop> using en-US culture
<coop> is less than <cop> using ordinal comparison
<co-op> is less than <cop> using en-US culture
<co-op> is less than <cop> using ordinal comparison

Las comparaciones lingüísticas dependen de la referencia cultural actual y del sistema operativo.Linguistic comparisons are dependent on the current culture, and are OS dependent. Debe tenerlo en cuenta cuando trabaje con comparaciones de cadenas.You must take that into account when you work with string comparisons.

Ordenación lingüística y búsqueda de cadenas en matricesLinguistic sorting and searching strings in arrays

En estos ejemplos se muestra cómo ordenar y buscar cadenas en una matriz mediante una comparación lingüística que depende de la referencia cultural actual.The following examples show how to sort and search for strings in an array using a linguistic comparison dependent on the current culture. Use los métodos Array estáticos que toman un parámetro System.StringComparer.You use the static Array methods that take a System.StringComparer parameter.

En este ejemplo se muestra cómo ordenar una matriz de cadenas con la referencia cultural actual:This example shows how to sort an array of strings using the current culture:

string[] lines = new string[]
{
    @"c:\public\textfile.txt",
    @"c:\public\textFile.TXT",
    @"c:\public\Text.txt",
    @"c:\public\testfile2.txt"
};

Console.WriteLine("Non-sorted order:");
foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

Console.WriteLine("\n\rSorted order:");

// Specify Ordinal to demonstrate the different behavior.
Array.Sort(lines, StringComparer.CurrentCulture);

foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

Una vez que se ordena la matriz, puede buscar entradas mediante una búsqueda binaria.Once the array is sorted, you can search for entries using a binary search. Una búsqueda binaria empieza en medio de la colección para determinar qué mitad de la colección debe contener la cadena buscada.A binary search starts in the middle of the collection to determine which half of the collection would contain the sought string. Cada comparación posterior divide la parte restante de la colección por la mitad.Each subsequent comparison subdivides the remaining part of the collection in half. La matriz se ordena con el elemento StringComparer.CurrentCulture.The array is sorted using the StringComparer.CurrentCulture. La función local ShowWhere muestra información sobre dónde se encuentra la cadena.The local function ShowWhere displays information about where the string was found. Si no se encuentra la cadena, el valor devuelto indica dónde estaría si se encontrara.If the string was not found, the returned value indicates where it would be if it were found.

string[] lines = new string[]
{
    @"c:\public\textfile.txt",
    @"c:\public\textFile.TXT",
    @"c:\public\Text.txt",
    @"c:\public\testfile2.txt"
};
Array.Sort(lines, StringComparer.CurrentCulture);

string searchString = @"c:\public\TEXTFILE.TXT";
Console.WriteLine($"Binary search for <{searchString}>");
int result = Array.BinarySearch(lines, searchString, StringComparer.CurrentCulture);
ShowWhere<string>(lines, result);

Console.WriteLine($"{(result > 0 ? "Found" : "Did not find")} {searchString}");

void ShowWhere<T>(T[] array, int index)
{
    if (index < 0)
    {
        index = ~index;

        Console.Write("Not found. Sorts between: ");

        if (index == 0)
            Console.Write("beginning of sequence and ");
        else
            Console.Write($"{array[index - 1]} and ");

        if (index == array.Length)
            Console.WriteLine("end of sequence.");
        else
            Console.WriteLine($"{array[index]}.");
    }
    else
    {
        Console.WriteLine($"Found at index {index}.");
    }
}

Ordenación de ordinales y búsqueda en coleccionesOrdinal sorting and searching in collections

Este código usa la clase de colección System.Collections.Generic.List<T> para almacenar cadenas.The following code uses the System.Collections.Generic.List<T> collection class to store strings. Las cadenas se ordenan mediante el método List<T>.Sort.The strings are sorted using the List<T>.Sort method. Este método necesita un delegado que compare y ordene dos cadenas.This method needs a delegate that compares and orders two strings. El método String.CompareTo proporciona esa función de comparación.The String.CompareTo method provides that comparison function. Ejecute el ejemplo y observe el orden.Run the sample and observe the order. Esta operación de ordenación usa una ordenación ordinal con distinción entre mayúsculas y minúsculas.This sort operation uses an ordinal case sensitive sort. Tendría que usar los métodos estáticos String.Compare para especificar reglas de comparación distintas.You would use the static String.Compare methods to specify different comparison rules.

List<string> lines = new List<string>
{
    @"c:\public\textfile.txt",
    @"c:\public\textFile.TXT",
    @"c:\public\Text.txt",
    @"c:\public\testfile2.txt"
};

Console.WriteLine("Non-sorted order:");
foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

Console.WriteLine("\n\rSorted order:");

lines.Sort((left, right) => left.CompareTo(right)); 
foreach (string s in lines)
{
    Console.WriteLine($"   {s}");
}

Una vez realizada la ordenación, se pueden hacer búsquedas en la lista de cadenas mediante una búsqueda binaria.Once sorted, the list of strings can be searched using a binary search. En este ejemplo se muestra cómo buscar la lista ordenada usando la misma función de comparación.The following sample shows how to search the sorted listed using the same comparison function. La función local ShowWhere muestra dónde está o debería estar el texto buscado:The local function ShowWhere shows where the sought text is or would be:

List<string> lines = new List<string>
{
    @"c:\public\textfile.txt",
    @"c:\public\textFile.TXT",
    @"c:\public\Text.txt",
    @"c:\public\testfile2.txt"
};
lines.Sort((left, right) => left.CompareTo(right));

string searchString = @"c:\public\TEXTFILE.TXT";
Console.WriteLine($"Binary search for <{searchString}>");
int result = lines.BinarySearch(searchString);
ShowWhere<string>(lines, result);

Console.WriteLine($"{(result > 0 ? "Found" : "Did not find")} {searchString}");

void ShowWhere<T>(IList<T> collection, int index)
{
    if (index < 0)
    {
        index = ~index;

        Console.Write("Not found. Sorts between: ");

        if (index == 0)
            Console.Write("beginning of sequence and ");
        else
            Console.Write($"{collection[index - 1]} and ");

        if (index == collection.Count)
            Console.WriteLine("end of sequence.");
        else
            Console.WriteLine($"{collection[index]}.");
    }
    else
    {
        Console.WriteLine($"Found at index {index}.");
    }
}

Asegúrese siempre de usar el mismo tipo de comparación para la ordenación y la búsqueda.Always make sure to use the same type of comparison for sorting and searching. Si se usan distintos tipos de comparación para la ordenación y la búsqueda se producen resultados inesperados.Using different comparison types for sorting and searching produces unexpected results.

Las clases de colección como System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey,TValue> y System.Collections.Generic.List<T> tienen constructores que toman un parámetro System.StringComparer cuando el tipo de los elementos o claves es string.Collection classes such as System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey,TValue>, and System.Collections.Generic.List<T> have constructors that take a System.StringComparer parameter when the type of the elements or keys is string. En general, debe usar estos constructores siempre que sea posible y especificar StringComparer.Ordinal u StringComparer.OrdinalIgnoreCase.In general, you should use these constructors whenever possible, and specify either StringComparer.Ordinal or StringComparer.OrdinalIgnoreCase.

Igualdad de referencia e internamiento de cadenaReference equality and string interning

Ninguno de los ejemplos ha usado ReferenceEquals.None of the samples have used ReferenceEquals. Este método determina si dos cadenas son el mismo objeto.This method determines if two strings are the same object. Esto puede conducir a resultados incoherentes en comparaciones de cadenas.This can lead to inconsistent results in string comparisons. En este ejemplo se muestra la característica de internamiento de cadenas de C#.The following example demonstrates the string interning feature of C#. Cuando un programa declara dos o más variables de cadena idénticas, el compilador lo almacena todo en la misma ubicación.When a program declares two or more identical string variables, the compiler stores them all in the same location. Mediante una llamada al método ReferenceEquals, puede ver que las dos cadenas realmente hacen referencia al mismo objeto en memoria.By calling the ReferenceEquals method, you can see that the two strings actually refer to the same object in memory. Use el método String.Copy para evitar el internamiento.Use the String.Copy method to avoid interning. Después de hacer la copia, las dos cadenas tienen diferentes ubicaciones de almacenamiento, aunque tengan el mismo valor.After the copy has been made, the two strings have different storage locations, even though they have the same value. Ejecute este ejemplo para mostrar que las cadenas a y b son internadas, lo que significa que comparten el mismo almacenamiento.Run the following sample to show that strings a and b are interned meaning they share the same storage. Las cadenas a y c no lo son.The strings a and c are not.

string a = "The computer ate my source code.";
string b = "The computer ate my source code.";

if (String.ReferenceEquals(a, b))
    Console.WriteLine("a and b are interned.");
else
    Console.WriteLine("a and b are not interned.");

string c = String.Copy(a);

if (String.ReferenceEquals(a, c))
    Console.WriteLine("a and c are interned.");
else
    Console.WriteLine("a and c are not interned.");

Nota

Cuando se prueba la igualdad de cadenas, debe usar los métodos que especifican explícitamente el tipo de comparación que va a realizar.When you test for equality of strings, you should use the methods that explicitly specify what kind of comparison you intend to perform. El código se vuelve mucho más legible y fácil de mantener.Your code is much more maintainable and readable. Use sobrecargas de los métodos de las clases System.String y System.Array que toman un parámetro de enumeración StringComparison.Use the overloads of the methods of the System.String and System.Array classes that take a StringComparison enumeration parameter. Especifique qué tipo de comparación se va a realizar.You specify which type of comparison to perform. Evite usar los operadores == y != cuando pruebe la igualdad.Avoid using the == and != operators when you test for equality. Los métodos de instancia String.CompareTo siempre realizan una comparación ordinal con distinción entre mayúsculas y minúsculas.The String.CompareTo instance methods always perform an ordinal case-sensitive comparison. Son adecuados principalmente para ordenar alfabéticamente las cadenas.They are primarily suited for ordering strings alphabetically.

Puede internalizar una cadena o recuperar una referencia a una cadena internalizada existente llamando al método String.Intern.You can intern a string or retrieve a reference to an existing interned string by calling the String.Intern method. Para determinar si una cadena se aplica el método Intern, llame al método String.IsInterned.To determine whether a string is interned, call the String.IsInterned method.

Vea tambiénSee also