Ao fazer comparações que não diferenciam maiúsculas de minúsculas, é mais eficiente converter a string em maiúsculas ou minúsculas? Isso importa mesmo?
É sugerido neste post do SO que o C # é mais eficiente com o ToUpper porque "a Microsoft o otimizou dessa maneira." Mas eu também li este argumento de que a conversão de ToLower vs. ToUpper depende do que suas strings contêm mais, e que normalmente as strings contêm mais caracteres minúsculos, o que torna ToLower mais eficiente.
Em particular, gostaria de saber:
- Existe uma maneira de otimizar ToUpper ou ToLower de forma que um seja mais rápido que o outro?
- É mais rápido fazer uma comparação sem distinção entre maiúsculas e minúsculas e por quê?
- Existe algum ambiente de programação (por exemplo, C, C #, Python, qualquer que seja) onde um caso é claramente melhor do que o outro e por quê?
fonte
Da Microsoft no MSDN:
Por quê? Da Microsoft :
Qual é o exemplo de um personagem que não pode fazer uma viagem de ida e volta?
.NET Fiddle
É por isso que, se você quiser fazer comparações sem distinção entre maiúsculas e minúsculas, converta as strings em maiúsculas, e não em minúsculas.
Portanto, se você tiver que escolher um, escolha Maiúsculas .
fonte
ToUpper()
lo se tornará 'SS' em muitos sistemas. Portanto, também não é possível fazer viagens de ida e volta.ToUpperInvariant()
, então ainda seria bom ver exemplos reais de porque maiúsculas é melhor do que minúsculasDe acordo com o MSDN , é mais eficiente passar as strings e dizer à comparação para ignorar maiúsculas e minúsculas:
Claro, se você estiver comparando uma corda repetidamente, isso pode não funcionar.
fonte
Com base em strings que tendem a ter mais entradas em minúsculas, ToLower deveria teoricamente ser mais rápido (muitas comparações, mas poucas atribuições).
Em C, ou ao usar elementos acessíveis individualmente de cada string (como strings C ou o tipo de string STL em C ++), é na verdade uma comparação de bytes - então comparar
UPPER
não é diferente delower
.Se você fosse sorrateiro e carregasse suas strings em
long
arrays, obteria uma comparação muito rápida de toda a string porque ela poderia comparar 4 bytes por vez. No entanto, o tempo de carregamento pode fazer com que não valha a pena.Por que você precisa saber o que é mais rápido? A menos que você esteja fazendo um monte de comparações métricas, uma execução alguns ciclos mais rápido é irrelevante para a velocidade de execução geral e soa como otimização prematura :)
fonte
s
et
em arrays de longs de modo que as strings sejam iguais se os arrays forem iguais, você precisa percorrer s e t até encontrar o'\0'
caractere de terminação (ou então você pode comparar o lixo após o final das strings, que pode ser um acesso ilegal à memória que invoca um comportamento indefinido). Mas então por que não fazer as comparações enquanto examina os personagens um por um? Com strings C ++, você provavelmente pode obter o comprimento e.c_str()
, converter em aelong *
comparar um prefixo de comprimento.size() - .size()%(sizeof long)
. Parece um pouco suspeito para mim, tho.long
s apenas para fins de comparação seria tolice. Mas se você está fazendo "muito" - posso ver um possível argumento para que seja feito.A Microsoft otimizou
ToUpperInvariant()
, nãoToUpper()
. A diferença é que invariante é mais amigável à cultura. Se você precisar fazer comparações que não diferenciam maiúsculas de minúsculas em strings que podem variar na cultura, use Invariante, caso contrário, o desempenho da conversão invariável não deve importar.Não posso dizer se ToUpper () ou ToLower () é mais rápido. Nunca tentei, pois nunca tive uma situação em que o desempenho importasse tanto.
fonte
Se você estiver fazendo comparação de strings em C #, é significativamente mais rápido usar .Equals () em vez de converter ambas as strings em maiúsculas ou minúsculas. Outra grande vantagem para usar .Equals () é que mais memória não é alocada para as 2 novas strings maiúsculas / minúsculas.
fonte
Realmente não deveria importar. Com caracteres ASCII, definitivamente não importa - são apenas algumas comparações e um pouco de mudança para qualquer direção. Unicode pode ser um pouco mais complicado, já que existem alguns caracteres que mudam de caixa de maneira estranha, mas realmente não deve haver nenhuma diferença a menos que seu texto esteja cheio desses caracteres especiais.
fonte
Fazendo isso da maneira certa, deve haver uma pequena e insignificante vantagem de velocidade se você converter para minúsculas, mas isso é, como muitos sugeriram, dependente da cultura e não é herdado na função, mas nas strings que você converte (muitas letras minúsculas significa poucas atribuições na memória) - converter para maiúsculas é mais rápido se você tiver uma string com muitas letras maiúsculas.
fonte
Eu queria alguns dados reais sobre isso, então puxei a lista completa de dois caracteres de byte que falham com
ToLower
ouToUpper
. Em seguida, executei este teste abaixo:using System; class Program { static void Main() { char[][] pairs = { new[]{'\u00E5','\u212B'},new[]{'\u00C5','\u212B'},new[]{'\u0399','\u1FBE'}, new[]{'\u03B9','\u1FBE'},new[]{'\u03B2','\u03D0'},new[]{'\u03B5','\u03F5'}, new[]{'\u03B8','\u03D1'},new[]{'\u03B8','\u03F4'},new[]{'\u03D1','\u03F4'}, new[]{'\u03B9','\u1FBE'},new[]{'\u0345','\u03B9'},new[]{'\u0345','\u1FBE'}, new[]{'\u03BA','\u03F0'},new[]{'\u00B5','\u03BC'},new[]{'\u03C0','\u03D6'}, new[]{'\u03C1','\u03F1'},new[]{'\u03C2','\u03C3'},new[]{'\u03C6','\u03D5'}, new[]{'\u03C9','\u2126'},new[]{'\u0392','\u03D0'},new[]{'\u0395','\u03F5'}, new[]{'\u03D1','\u03F4'},new[]{'\u0398','\u03D1'},new[]{'\u0398','\u03F4'}, new[]{'\u0345','\u1FBE'},new[]{'\u0345','\u0399'},new[]{'\u0399','\u1FBE'}, new[]{'\u039A','\u03F0'},new[]{'\u00B5','\u039C'},new[]{'\u03A0','\u03D6'}, new[]{'\u03A1','\u03F1'},new[]{'\u03A3','\u03C2'},new[]{'\u03A6','\u03D5'}, new[]{'\u03A9','\u2126'},new[]{'\u0398','\u03F4'},new[]{'\u03B8','\u03F4'}, new[]{'\u03B8','\u03D1'},new[]{'\u0398','\u03D1'},new[]{'\u0432','\u1C80'}, new[]{'\u0434','\u1C81'},new[]{'\u043E','\u1C82'},new[]{'\u0441','\u1C83'}, new[]{'\u0442','\u1C84'},new[]{'\u0442','\u1C85'},new[]{'\u1C84','\u1C85'}, new[]{'\u044A','\u1C86'},new[]{'\u0412','\u1C80'},new[]{'\u0414','\u1C81'}, new[]{'\u041E','\u1C82'},new[]{'\u0421','\u1C83'},new[]{'\u1C84','\u1C85'}, new[]{'\u0422','\u1C84'},new[]{'\u0422','\u1C85'},new[]{'\u042A','\u1C86'}, new[]{'\u0463','\u1C87'},new[]{'\u0462','\u1C87'} }; int upper = 0, lower = 0; foreach (char[] pair in pairs) { Console.Write( "U+{0:X4} U+{1:X4} pass: ", Convert.ToInt32(pair[0]), Convert.ToInt32(pair[1]) ); if (Char.ToUpper(pair[0]) == Char.ToUpper(pair[1])) { Console.Write("ToUpper "); upper++; } else { Console.Write(" "); } if (Char.ToLower(pair[0]) == Char.ToLower(pair[1])) { Console.Write("ToLower"); lower++; } Console.WriteLine(); } Console.WriteLine("upper pass: {0}, lower pass: {1}", upper, lower); } }
Resultado abaixo. Observe que também testei com as
Invariant
versões e o resultado foi exatamente o mesmo. Curiosamente, um dos pares falha com ambos. Mas com base nisso, ToUpper é a melhor opção .fonte