Como comparar cadeias de caracteres no C#How to compare strings in C#

Você compara cadeias de caracteres para responder uma dessas duas perguntas: "Essas duas cadeias de caracteres são iguais?"You compare strings to answer one of two questions: "Are these two strings equal?" ou "Em que ordem essas cadeias de caracteres devem ser colocadas ao classificá-las?"or "In what order should these strings be placed when sorting them?"

Essas duas perguntas são complicadas devido a fatores que afetam as comparações de cadeia de caracteres:Those two questions are complicated by factors that affect string comparisons:

  • Você pode escolher uma comparação ordinal ou linguística.You can choose an ordinal or linguistic comparison.
  • Você pode escolher se o uso de maiúsculas faz diferença.You can choose if case matters.
  • Você pode escolher comparações específicas de cultura.You can choose culture specific comparisons.
  • As comparações linguísticas dependem da plataforma e da cultura.Linguistic comparisons are culture and platform dependent.

Observação

Os exemplos de C# neste artigo são executados no executador de código embutido Try.NET e no playground.The C# examples in this article run in the Try.NET inline code runner and playground. Clique no botão Executar para executar um exemplo em uma janela interativa.Select the Run button to run an example in an interactive window. Ao executar o código, é possível modificá-lo e executar o código modificado clicando em Executar novamente.Once you execute the code, you can modify it and run the modified code by selecting Run again. O código modificado será executado na janela interativa ou, se a compilação falhar, a janela interativa exibirá todos as mensagens de erro do compilador C#.The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C# compiler error messages.

Ao comparar cadeias de caracteres, você pode definir uma ordem entre elas.When you compare strings, you define an order among them. As comparações são usadas para classificar uma sequência de cadeias de caracteres.Comparisons are used to sort a sequence of strings. Com a sequência em uma ordem conhecida, fica mais fácil de pesquisar, tanto para softwares quanto para os usuários.Once the sequence is in a known order, it is easier to search, both for software and for humans. Outras comparações podem verificar se as cadeias de caracteres são iguais.Other comparisons may check if strings are the same. Essas verificações são semelhantes a igualdade, mas algumas diferenças, como diferenças entre maiúsculas e minúsculas, podem ser ignoradas.These sameness checks are similar to equality, but some differences, such as case differences, may be ignored.

Comparações ordinárias padrãoDefault ordinal comparisons

As operações mais comuns, String.CompareTo e String.Equals ou String.Equality, usam uma comparação ordinal, uma comparação que diferencia maiúsculas de minúsculas e a cultura atual.The most common operations, String.CompareTo and String.Equals or String.Equality use an ordinal comparison, a case-sensitive comparison, and use the current culture. Os resultados são mostrados no exemplo a seguir.The results are shown in the following example.

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

bool result = root.Equals(root2);
int comparison = root.CompareTo(root2);
Console.WriteLine($"Ordinal comparison: <{root}> and <{root2}> are {(result ? "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");

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

As comparações ordinais não consideram regras linguísticas ao comparar cadeias de caracteres.Ordinal comparisons do not take linguistic rules into account when comparing strings. Elas vão comparar cada caractere das cadeias de caracteres.They will compare the strings character by character. As comparações que diferenciam letras maiúsculas e minúsculas usam a capitalização em suas comparações.Case-sensitive comparisons use capitalization in their comparisons. O ponto mais importante sobre esses métodos de comparação padrão é que, como eles usam a cultura atual, os resultados dependem das configurações de idioma e localidade do computador em que são executadas.The most important point about these default comparison methods is that because they use the current culture, the results depend on the locale and language settings of the machine where they run. Essas comparações são inadequadas para comparações em que a ordem deve ser consistente entre computadores ou localidades.These comparisons are unsuitable for comparisons where order should be consistent across machines or locations.

Comparações ordinais que não diferenciam maiúsculas de minúsculasCase-insensitive ordinal comparisons

O método String.Equals permite que você especifique um valor StringComparison de StringComparison.OrdinalIgnoreCaseThe String.Equals method enables you to specify a StringComparison value of StringComparison.OrdinalIgnoreCase para especificar uma comparação que não diferencia maiúsculas de minúsculas.to specify a case-insensitive comparison. Também há um método Compare estático que inclui um argumento booliano para especificar comparações que não diferenciam maiúsculas de minúsculas.There is also a static Compare method that includes a boolean argument to specify case-insensitive comparisons. Eles são mostrados no código a seguir: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, ignoreCase: true);

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

Comparações linguísticasLinguistic comparisons

As cadeias de caracteres também podem ser ordenadas usando regras linguísticas para a cultura atual.Strings can also be ordered using linguistic rules for the current culture. Às vezes, isso é conhecido como "ordem de classificação de palavra".This is sometimes referred to as "word sort order." Quando você executa uma comparação linguística, alguns caracteres Unicode não alfanuméricos podem ter pesos especiais atribuídos.When you perform a linguistic comparison, some nonalphanumeric Unicode characters might have special weights assigned. Por exemplo, o hífen "-" pode ter um peso muito pequeno atribuído, de modo que "co-op" e "coop" apareçam próximos um do outro na ordem de classificação.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. Além disso, alguns caracteres Unicode podem ser equivalentes a uma sequência de caracteres alfanuméricos.In addition, some Unicode characters may be equivalent to a sequence of alphanumeric characters. O exemplo a seguir usa a frase "They dance in the street."The following example uses the phrase "They dance in the street." em alemão com o "ss" e 'ß'.in German with the "ss" and 'ß'. Linguisticamente (no Windows), "ss" é igual ao eszett alemão: caractere 'ß' nas culturas "en-US" e "de-DE".Linguistically (in Windows), "ss" is equal to the German Essetz: 'ß' character in both "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 exemplo demonstra a natureza dependente de sistema operacional das comparações linguísticas.This sample demonstrates the operating system dependent nature of linguistic comparisons. O host da janela interativa é um host Linux.The host for the interactive window is a Linux host. As comparações de linguísticas e ordinais produzem os mesmos resultados.The linguistic and ordinal comparisons produce the same results. Se você executar este mesmo exemplo em um host do Windows, a saída será a seguinte: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

No Windows, a ordem de classificação de "cop", "coop" e "co-op" muda quando você muda de uma comparação linguística para uma comparação ordinal.On Windows, the sort order of "cop", "coop", and "co-op" change when you change from a linguistic comparison to an ordinal comparison. As duas frases em alemão também são comparadas de forma diferente ao usar os tipos diferentes de comparação.The two German sentences also compare differently using the different comparison types.

Comparações usando culturas específicasComparisons using specific cultures

Este exemplo armazena CultureInfo para a cultura atual.This sample stores CultureInfo for the current culture. A cultura original pode ser definida e recuperada no objeto de thread atual.The original culture can be set and retrieved on the current thread object. As comparações são executadas usando o valor CurrentCulture para garantir uma comparação específica da cultura.The comparisons are performed using the CurrentCulture value to ensure a culture-specific comparison.

A cultura usada afeta as comparações linguísticas.The culture used affects linguistic comparisons. O exemplo a seguir mostra os resultados da comparação das duas frases em alemão usando a cultura "en-US" e a cultura "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.IgnoreNonSpace);
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.IgnoreNonSpace);
Console.WriteLine($"Comparing in {de.Name} returns {i}.");

bool b = String.Equals(first, second, StringComparison.CurrentCulture);
Console.WriteLine($"The two strings {(b == true ? "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.IgnoreNonSpace);
    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");
}

As comparações que diferenciam cultura normalmente são usadas para comparar e classificar cadeias de caracteres inseridas por usuários com outras cadeias de caracteres inseridas por usuários.Culture-sensitive comparisons are typically used to compare and sort strings input by users with other strings input by users. Os caracteres e as convenções de classificação dessas cadeias de caracteres podem variar de acordo com a localidade do computador do usuário.The characters and sorting conventions of these strings might vary depending on the locale of the user's computer. Até mesmo cadeias de caracteres que contêm caracteres idênticos podem ser classificadas de formas diferentes dependendo da cultura do thread atual.Even strings that contain identical characters might sort differently depending on the culture of the current thread. Além disso, experimente este código de exemplo localmente em um computador Windows, e você verá os seguintes 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

As comparações linguísticas dependem da cultura atual e são dependentes do SO.Linguistic comparisons are dependent on the current culture, and are OS dependent. Você deve considerar isso ao trabalhar com comparações de cadeia de caracteres.You must take that into account when you work with string comparisons.

Classificação linguística e cadeias de caracteres de pesquisa em matrizesLinguistic sorting and searching strings in arrays

Os exemplos a seguir mostram como classificar e pesquisar cadeias de caracteres em uma matriz usando uma comparação linguística que depende da cultura atual.The following examples show how to sort and search for strings in an array using a linguistic comparison dependent on the current culture. Use os métodos Array estáticos que aceitam um parâmetro System.StringComparer.You use the static Array methods that take a System.StringComparer parameter.

Este exemplo mostra como classificar uma matriz de cadeias de caracteres usando a cultura atual: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}");
}

Depois que a matriz é classificada, você pode procurar as entradas usando uma pesquisa binária.Once the array is sorted, you can search for entries using a binary search. Uma pesquisa binária é iniciada no meio da coleção para determinar qual metade da coleção contém a cadeia de caracteres procurada.A binary search starts in the middle of the collection to determine which half of the collection would contain the sought string. Cada comparação subsequente subdivide a parte restante da coleção na metade.Each subsequent comparison subdivides the remaining part of the collection in half. A matriz é classificada usando StringComparer.CurrentCulture.The array is sorted using StringComparer.CurrentCulture. A função local ShowWhere exibe informações sobre o local em que a cadeia de caracteres foi encontrada.The local function ShowWhere displays information about where the string was found. Se a cadeia de caracteres não for encontrada, o valor retornado indicará o local em que estaria se fosse encontrada.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}.");
    }
}

Classificação ordinal e pesquisa em coleçõesOrdinal sorting and searching in collections

O código a seguir usa a classe de coleção System.Collections.Generic.List<T> para armazenar cadeias de caracteres.The following code uses the System.Collections.Generic.List<T> collection class to store strings. As cadeias de caracteres são classificadas usando o método List<T>.Sort.The strings are sorted using the List<T>.Sort method. Esse método precisa de um delegado que compara e ordena as duas cadeias de caracteres.This method needs a delegate that compares and orders two strings. O método String.CompareTo fornece essa função de comparação.The String.CompareTo method provides that comparison function. Execute o exemplo e observe a ordem.Run the sample and observe the order. Essa operação de classificação usa uma classificação ordinal que diferencia maiúsculas e minúsculas.This sort operation uses an ordinal case sensitive sort. Você usaria os métodos String.Compare estáticos para especificar regras de comparação diferentes.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}");
}

Uma vez classificada, a lista de cadeias de caracteres pode ser pesquisada usando uma pesquisa binária.Once sorted, the list of strings can be searched using a binary search. O exemplo a seguir mostra como pesquisar a lista classificada usando a mesma função de comparação.The following sample shows how to search the sorted listed using the same comparison function. A função local ShowWhere mostra o local em que o texto procurado está ou deveria estar: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}.");
    }
}

Use sempre o mesmo tipo de comparação para classificação e pesquisa.Always make sure to use the same type of comparison for sorting and searching. O uso de tipos diferentes de comparação para classificação e pesquisa produz resultados inesperados.Using different comparison types for sorting and searching produces unexpected results.

Classes de coleção como System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey,TValue> e System.Collections.Generic.List<T> têm construtores que usam um parâmetro System.StringComparer quando o tipo dos elementos ou chaves é 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. Em geral, você deve usar esses construtores sempre que possível e especificar StringComparer.Ordinal ou StringComparer.OrdinalIgnoreCase.In general, you should use these constructors whenever possible, and specify either StringComparer.Ordinal or StringComparer.OrdinalIgnoreCase.

Igualdade de referência e centralização de cadeia de caracteresReference equality and string interning

Nenhum dos exemplos usou ReferenceEquals.None of the samples have used ReferenceEquals. Este método determina se duas cadeias de caracteres são o mesmo objeto.This method determines if two strings are the same object. Isso pode levar a resultados inconsistentes em comparações de cadeia de caracteres.This can lead to inconsistent results in string comparisons. O exemplo a seguir demonstra o recurso de centralização da cadeia de caracteres do C#.The following example demonstrates the string interning feature of C#. Quando um programa declara duas ou mais variáveis de cadeia de caracteres idênticas, o compilador armazena todas no mesmo local.When a program declares two or more identical string variables, the compiler stores them all in the same location. Chamando o método ReferenceEquals, você pode ver que as duas cadeias de caracteres na verdade se referem ao mesmo objeto na memória.By calling the ReferenceEquals method, you can see that the two strings actually refer to the same object in memory. Use o método String.Copy para evitar a centralização.Use the String.Copy method to avoid interning. Depois que a cópia for feita, as duas cadeias de caracteres terão locais de armazenamento diferentes, mesmo que tenham o mesmo valor.After the copy has been made, the two strings have different storage locations, even though they have the same value. Execute o exemplo a seguir para mostrar que as cadeias de caracteres a e b são centralizadas, ou seja, que elas compartilham o mesmo armazenamento.Run the following sample to show that strings a and b are interned meaning they share the same storage. As cadeias de caracteres a e c não são.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.");

Observação

Quando você testa cadeias de caracteres quanto a igualdade, é necessário usar os métodos que especificam explicitamente o tipo de comparação que você pretende executar.When you test for equality of strings, you should use the methods that explicitly specify what kind of comparison you intend to perform. O código fica muito mais legível e fácil de manter.Your code is much more maintainable and readable. Use as sobrecargas dos métodos das classes System.String e System.Array que aceitam um parâmetro de enumeração StringComparison.Use the overloads of the methods of the System.String and System.Array classes that take a StringComparison enumeration parameter. Você especifica o tipo de comparação a ser executado.You specify which type of comparison to perform. Evite usar os operadores == e != ao testar a igualdade.Avoid using the == and != operators when you test for equality. Os métodos de instância String.CompareTo sempre executam uma comparação ordinal que diferencia maiúsculas de minúsculas.The String.CompareTo instance methods always perform an ordinal case-sensitive comparison. Basicamente, eles são adequados para colocar cadeias de caracteres em ordem alfabética.They are primarily suited for ordering strings alphabetically.

Consulte tambémSee also