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:The most common operations:

usar uma comparação ordinal, uma comparação que diferencia maiúsculas de minúsculas e a cultura atual.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);
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")}");               

A comparação ordinal padrão não considera regras linguísticas ao comparar cadeias de caracteres.The default ordinal comparison does not take linguistic rules into account when comparing strings. Ela compara o valor binário de cada objeto Char em duas cadeias de caracteres.It compares the binary value of each Char object in two strings. Como resultado, a comparação ordinal padrão também diferencia maiúsculas de minúsculas.As a result, the default ordinal comparison is also case-sensitive.

Observe que o teste de igualdade com String.Equals e String.Equality difere da comparação de cadeias de caracteres usando os métodos String.CompareTo e 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. Embora os testes de igualdade façam uma comparação ordinal com distinção entre maiúsculas e minúsculas, o método de comparação faz uma comparação que diferencia cultura e maiúsculas de minúsculas usando a cultura atual.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. Como os métodos de comparação padrão geralmente fazem diferentes tipos de comparações, recomendamos que você sempre esclareça a intenção do seu código, chamando uma sobrecarga que especifica explicitamente o tipo de comparação a ser feita.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.

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

O método String.Equals(String, StringComparison) permite que você especifique um valor StringComparison de StringComparison.OrdinalIgnoreCaseThe String.Equals(String, StringComparison) method enables you to specify a StringComparison value of StringComparison.OrdinalIgnoreCase para uma comparação ordinal que não diferencia maiúsculas de minúsculas.for a case-insensitive ordinal comparison. Há também um método String.Compare(String, String, StringComparison) estático que fará uma comparação ordinal sem distinção entre maiúsculas e minúsculas se você especificar um valor de StringComparison.OrdinalIgnoreCase para o 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. 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, 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");

Ao fazer uma comparação ordinal sem distinção entre maiúsculas e minúsculas, esses métodos usam as convenções de maiúsculas e minúsculas da cultura invariável.When performing a case-insensitive ordinal comparison, these methods use the casing conventions of the invariant culture.

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 instâncias Char.In addition, some Unicode characters may be equivalent to a sequence of Char instances. 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” (U+0073 U+0073) em uma cadeia de caracteres e ‘ß’ (U+00DF) em outra.in German with the "ss" (U+0073 U+0073) in one string and 'ß' (U+00DF) in another. Linguisticamente (no Windows), “ss” é igual ao Essetz alemão: caractere ‘ß’ nas culturas “en-US” e “de-DE”.Linguistically (in Windows), "ss" is equal to the German Essetz: 'ß' 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 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 objetos CultureInfo para as culturas en-US e de-DE.This sample stores CultureInfo objects for the en-US and de-DE cultures. As comparações são feitas usando um objeto CultureInfo para garantir uma comparação específica da cultura.The comparisons are performed using a CultureInfo object 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.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");
}

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 o StringComparer.CurrentCulture.The array is sorted using the 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.

Você pode internalizar uma cadeia de caracteres ou recuperar uma referência a uma cadeia de caracteres interna existente chamando o 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 se uma cadeia de caracteres está internalizada, chame o método String.IsInterned.To determine whether a string is interned, call the String.IsInterned method.

Consulte tambémSee also