O que geralmente é melhor usar - StringComparison.OrdinalIgnoreCase ou StringComparison.InvariantCultureIgnoreCase?

161

Eu tenho algum código como este:

If key.Equals("search", StringComparison.OrdinalIgnoreCase) Then
    DoSomething()
End If

Eu não ligo para o caso. Devo usar OrdinalIgnoreCase, InvariantCultureIgnoreCaseou CurrentCultureIgnoreCase?

Dave Haynes
fonte
2
Verifique se é realmente útil para esta discussão. Minha sugestão para usar ordianlignorecase para comparação. blogs.msdn.com/b/noahc/archive/2007/06/29/…
UmaMaheswaran
Considere a resposta altamente votada na comparação de cadeias
Michael Freidgeim
No geral, depende muito de que tipo de coisa você está comparando. Especificamente, se é uma entrada do usuário dependente da cultura ou material interno. Você não quer que a cultura do PC atrapalhe a comparação de cadeias de código interno.
Nyerguds

Respostas:

179

O .Net Docs mais recente agora tem uma tabela para ajudá-lo a decidir qual é o melhor para usar em sua situação.

Do MSDN " Novas recomendações para usar seqüências de caracteres no Microsoft .NET 2.0 "

Resumo: Os proprietários de código que usavam anteriormente a InvariantCulturecomparação, a composição e a classificação de seqüências de caracteres devem considerar o uso de um novo conjunto de Stringsobrecargas no Microsoft .NET 2.0. Especificamente, os dados projetados para serem independentes de cultura e linguisticamente irrelevantes devem começar a especificar sobrecargas usando o StringComparison.Ordinalou os StringComparison.OrdinalIgnoreCasemembros da nova StringComparisonenumeração. Eles impõem uma comparação de byte a byte semelhante strcmpàquela que não apenas evita bugs da interpretação linguística de seqüências essencialmente simbólicas, mas fornece melhor desempenho.

Robert Taylor
fonte
126
Para dar um exemplo de diferença, considere as duas cadeias "Straße"e "STRASSE". Ao usar OrdinalIgnoreCaseos Equalsretornos false, considerando InvariantCultureIgnoreCaseque eles são iguais.
Jeppe Stig Nielsen
63

Tudo depende

Comparar strings unicode é difícil:

A implementação de pesquisas e comparações de strings Unicode no software de processamento de texto deve levar em consideração a presença de pontos de código equivalentes. Na ausência desse recurso, os usuários que pesquisam uma sequência específica de pontos de código não conseguiriam encontrar outros glifos visualmente indistinguíveis que tenham uma representação de ponto de código diferente, mas canonicamente equivalente.

veja: http://en.wikipedia.org/wiki/Unicode_equivalence


Se você está tentando comparar duas cadeias unicode de uma maneira que não diferencia maiúsculas de minúsculas e deseja que funcione EM TODA PARTE , você tem um problema impossível.

O exemplo clássico é o turco i , que quando maiúsculo se torna © (observe o ponto)

Por padrão, a estrutura .Net geralmente usa o CurrentCulture para funções relacionadas a cadeias, com uma exceção muito importante .Equalsque usa uma comparação ordinal (byte a byte).

Isso leva, por design, às várias funções de seqüência de caracteres que se comportam de maneira diferente, dependendo da cultura do computador.


No entanto, às vezes queremos uma comparação "de uso geral", sem distinção entre maiúsculas e minúsculas.

Por exemplo, você pode querer que sua comparação de cadeias se comporte da mesma maneira, não importa em que computador seu aplicativo esteja instalado.

Para conseguir isso, temos 3 opções:

  1. Defina a cultura explicitamente e faça uma comparação sem distinção entre maiúsculas e minúsculas usando regras de equivalência unicode.
  2. Defina a cultura como Cultura invariável e execute comparação sem distinção entre maiúsculas e minúsculas usando regras de equivalência unicode.
  3. Use OrdinalIgnoreCase que maiúscula a seqüência de caracteres usando o InvariantCulture e, em seguida, execute uma comparação de byte a byte.

As regras de equivalência Unicode são complicadas, o que significa que o método 1) ou 2) é mais caro que OrdinalIgnoreCase. O fato de OrdinalIgnoreCasenão executar nenhuma normalização unicode especial significa que algumas seqüências que são renderizadas da mesma maneira na tela do computador não serão consideradas idênticas. Por exemplo: "\u0061\u030a"e "\u00e5"ambos renderizam å. No entanto, em uma comparação ordinal será considerado diferente.

A escolha que você escolher depende muito do aplicativo que você está criando.

  • Se eu estivesse escrevendo um aplicativo de linha de negócios usado apenas por usuários turcos, certamente usaria o método 1.
  • Se eu apenas precisasse de uma comparação simples "falsa" sem distinção entre maiúsculas e minúsculas, por exemplo, um nome de coluna em um banco de dados, que geralmente é inglês, provavelmente usaria o método 3.

A Microsoft tem seu conjunto de recomendações com diretrizes explícitas. No entanto, é realmente importante entender a noção de equivalência unicode antes de abordar esses problemas.

Além disso, lembre-se de que OrdinalIgnoreCase é um tipo muito especial de animal, que está escolhendo um pouco de comparação ordinal com alguns misturados em aspectos lexicográficos. Isso pode ser confuso.

Sam Saffron
fonte
4

Eu acho que depende da sua situação. Como as comparações ordinais estão realmente observando os valores numéricos Unicode dos caracteres, elas não serão a melhor opção quando você estiver classificando em ordem alfabética. Para comparações de strings, ordinal seria um pouco mais rápido.

Bullines
fonte
1

Depende do que você quer, embora eu coíbe de InvariantCulture menos que você está muito certo de que você nunca mais vai querer localizar o código para outras línguas. Use CurrentCulture.

Além disso, OrdinalIgnoreCase deve respeitar os números, que podem ou não ser o que você deseja.

Joel Coehoorn
fonte
1
Já escreveu código VB6 em um ambiente de idioma misto? Você pode criar código que seja compilado em um PC com o código do idioma francês, mas não será compilado em PCs com o código do idioma inglês, porque qualquer número armazenado nos recursos do formulário usa o formato do código do idioma atual. Eu diria que você precisa adotar a abordagem oposta: tenha muito cuidado ao usar a cultura atual. Sempre pense se o seu sistema ainda funcionará quando os dados forem movidos entre culturas. A mesma coisa com os fusos horários.
Wim Coenen #
Eu concordo com a resposta "depende". apesar de não seguir o bit "respeito aos números"?
Sam Saffron
-1

A resposta muito simples é que, a menos que você esteja usando turco, não precisará usar o InvariantCulture.

Veja o seguinte link:

Em C #, qual é a diferença entre ToUpper () e ToUpperInvariant ()?

TheMoot
fonte
5
Essa resposta pode ser simples, mas também está muito errada. O "eu" turco é apenas um exemplo , existem muitas outras armadilhas possíveis.
Ohad Schneider
Quais mais armadilhas? Eu apenas conheço o caso do problema turco.
HelloWorld
Sim, além do turco, há azeri. Mas é isso.
Jim Balter