Comparação de cadeias sem distinção entre maiúsculas e minúsculas em C ++ [fechado]
373
Qual é a melhor maneira de fazer comparação de strings sem distinção entre maiúsculas e minúsculas no C ++ sem transformar uma string em maiúsculas ou minúsculas?
Indique se os métodos são compatíveis com Unicode e como são portáteis.
@ [Adam] (# 11679): Embora essa variante seja boa em termos de usabilidade, é ruim em termos de desempenho porque cria cópias desnecessárias. Posso ignorar algo, mas acredito que a melhor maneira (não-Unicode) é usar std::stricmp. Caso contrário, leia o que Herb tem a dizer .
Konrad Rudolph
Em c, um geralmente foi forçado toupper a corda toda, então, comparar essa maneira - ou rolar seus próprios comparar: P
@ Mσᶎ esta pergunta também tem essa resposta, com a ressalva importante que strcasecmpnão faz parte do padrão e está ausente em pelo menos um compilador comum.
Mark Ransom
Respostas:
318
O Boost inclui um algoritmo útil para isso:
#include<boost/algorithm/string.hpp>// Or, for fewer header dependencies://#include <boost/algorithm/string/predicate.hpp>
std::string str1 ="hello, world!";
std::string str2 ="HELLO, WORLD!";if(boost::iequals(str1, str2)){// Strings are identical}
Não, porque UTF-8 permite cordas idênticas a ser codificado com diferentes códigos binários, devido à acentos, colheitadeiras, questões bidi, etc.
vy32
10
@ vy32 Isso é absolutamente incorreto! As combinações UTF-8 são mutuamente exclusivas. Ele sempre deve usar a representação mais curta possível; caso contrário, é uma sequência UTF-8 mal formada ou um ponto de código que deve ser tratado com cuidado.
Wiz
48
@ Wiz, você está ignorando o problema da normalização de strings Unicode. ñ pode ser representado como uma combinação ˜ seguida por um n ou com um caractere ñ. Você precisa usar a normalização de seqüência de caracteres Unicode antes de realizar a comparação. Consulte o Relatório Técnico Unicode # 15, unicode.org/reports/tr15
Aproveite o padrão char_traits. Lembre-se de que a std::stringé de fato um typedef para std::basic_string<char>, ou mais explicitamente std::basic_string<char, std::char_traits<char> >,. O char_traitstipo descreve como os caracteres são comparados, como eles copiam, como são convertidos etc. Tudo o que você precisa fazer é digitar uma nova sequência de caracteres basic_stringe fornecer a ela seu próprio costume char_traitsque compara maiúsculas e minúsculas.
Até onde eu sei por experiência própria, isso torna seu novo tipo de string incompatível com std :: string.
Zan Lynx
8
Claro que sim - para seu próprio bem. Uma cadeia que não diferencia maiúsculas de minúsculas é outra coisa:, typedef std::basic_string<char, ci_char_traits<char> > istringnão typedef std::basic_string<char, std::char_traits<char> > string.
Andreas Spindler
232
"Tudo o que você precisa fazer ..."
Tim MB
3
Provavelmente @ Nathan usar um compilador que é capaz de realizar CSE básicas sobre o código ...
O paramagnética Croissant
17
Qualquer construção de linguagem que force tal insanidade nesse caso trivial deve e pode ser abandonada sem arrependimentos.
Erik Aronesty
86
O problema com o impulso é que você precisa se conectar e depender do impulso. Não é fácil em alguns casos (por exemplo, android).
E usar char_traits significa tudo suas comparações não maiúsculas de minúsculas, o que geralmente não é o que você deseja.
Isso deve ser suficiente. Deve ser razoavelmente eficiente. Não lida com unicode ou qualquer coisa.
bool iequals(const string& a,const string& b){unsignedint sz = a.size();if(b.size()!= sz)returnfalse;for(unsignedint i =0; i < sz;++i)if(tolower(a[i])!= tolower(b[i]))returnfalse;returntrue;}
Atualização: versão bônus do C ++ 14 ( #include <algorithm>):
Na verdade, a biblioteca de cadeias de impulso é uma biblioteca apenas de cabeçalho, portanto, não há necessidade de vincular a nada. Além disso, você pode usar o utilitário 'bcp' do boost para copiar apenas os cabeçalhos de string na sua árvore de origem, para que você não precise exigir a biblioteca completa do boost.
Gretchen
Ah, eu não sabia sobre o bcp, parece realmente útil. Obrigado pela informação!
Timmmm 13/03/11
9
É bom saber uma versão simples e sem dependência de impulso.
Deqing 17/05
2
@Anna A biblioteca de textos de impulso precisa ser criada e vinculada. Ele usa o IBM ICU.
Behrouz.M
Também disponível com C ++ 11
marian
58
Se você estiver em um sistema POSIX, poderá usar o strcasecmp . Essa função não faz parte do padrão C, no entanto, nem está disponível no Windows. Isso fará uma comparação sem distinção entre maiúsculas e minúsculas em caracteres de 8 bits, desde que o código do idioma seja POSIX. Se o código do idioma não for POSIX, os resultados serão indefinidos (portanto, pode ser uma comparação localizada ou não). Um equivalente de caracteres largos não está disponível.
Caso contrário, um grande número de implementações históricas da biblioteca C possui as funções stricmp () e strnicmp (). O Visual C ++ no Windows renomeou todos esses itens, com um sublinhado como prefixo, porque eles não fazem parte do padrão ANSI; nesse sistema, eles são chamados _stricmp ou _strnicmp . Algumas bibliotecas também podem ter funções equivalentes a caracteres largos ou multibyte (normalmente denominadas, por exemplo, wcsicmp, mbcsicmp e assim por diante).
C e C ++ ignoram amplamente os problemas de internacionalização, portanto não há uma boa solução para esse problema, exceto o uso de uma biblioteca de terceiros. Confira IBM ICU (Componentes Internacionais para Unicode) se você precisar de uma biblioteca robusta para C / C ++. A UTI é para os sistemas Windows e Unix.
Você está falando de uma comparação sem distinção entre maiúsculas e minúsculas ou uma comparação Unicode normalizada completa?
Uma comparação idiota não encontrará cadeias que podem ser iguais, mas não são binárias iguais.
Exemplo:
U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A)+ U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).
São todos equivalentes, mas eles também têm diferentes representações binárias.
Dito isto, a Normalização Unicode deve ser uma leitura obrigatória, especialmente se você planeja dar suporte ao Hangul, Thaï e outros idiomas asiáticos.
Além disso, a IBM praticamente patenteou os algoritmos Unicode mais otimizados e os disponibilizou publicamente. Eles também mantêm uma implementação: IBM ICU
Você pode usar strcasecmpno Unix ou stricmpno Windows.
Uma coisa que não foi mencionada até agora é que, se você estiver usando strings stl com esses métodos, é útil comparar primeiro o comprimento das duas strings, pois essas informações já estão disponíveis para você na classe de strings. Isso poderia impedir a comparação cara de uma string, se as duas strings que você está comparando não tiverem o mesmo comprimento em primeiro lugar.
Como determinar o comprimento de uma string consiste em iterar todos os caracteres da string e compará-la com 0, há realmente muita diferença entre isso e apenas comparar as strings imediatamente? Eu acho que você obtém melhor localidade de memória no caso em que as duas seqüências não coincidem, mas provavelmente quase o tempo de execução é 2x em caso de uma correspondência.
Isso é um fato pouco divertido, mas tem pouca influência aqui. strcasecmp () e stricmp () usam seqüências de caracteres C não decoradas, portanto não há std :: string envolvido.
uliwitness
3
Esses métodos retornarão -1 se você comparar "a" vs "ab". Os comprimentos são diferentes, mas "a" vem antes de "ab". Portanto, a simples comparação dos comprimentos não é viável se o chamador se importar com o pedido.
Ironicamente, os "códigos de caracteres amplos" da Microsoft NÃO são limpos por unicode porque não tratam da normalização unicode.
vy32
13
Estou tentando reunir uma boa resposta de todas as postagens, então me ajude a editar isso:
Aqui está um método para fazer isso, embora ele transforme as seqüências de caracteres e não seja compatível com Unicode, ele deve ser portátil, o que é uma vantagem:
Pelo que li, isso é mais portátil que o stricmp () porque o stricmp () não faz parte da biblioteca std, mas é implementado apenas pela maioria dos fornecedores de compiladores.
Para obter uma implementação realmente compatível com Unicode, parece que você deve sair da biblioteca std. Uma boa biblioteca de terceiros é o IBM ICU (International Components for Unicode)
O boost :: iequals também fornece um utilitário bastante bom para fazer esse tipo de comparação.
Não existe uma maneira embutida com std :: string?
WilliamKF
6
Não, não existe.
Dean Harding
3
"... por que se preocupar quando já está pronto?" - e se você não estiver usando o Boost? O OP não tinha a etiqueta com a pergunta.
JWW
11
FYI strcmp()e stricmp()são vulneráveis ao estouro de buffer, pois apenas processam até atingir um terminador nulo. É mais seguro de usar _strncmp()e _strnicmp().
É verdade, embora overREADing um buffer seja significativamente menos perigoso que overWRITEing a buffer.
23811 Adam Rosenfield
4
stricmp()e strnicmp()não fazem parte do padrão POSIX :-( No entanto, você pode encontrar strcasecmp(), strcasecmp_l(), strncasecmp()e strncasecmp_l()em POSIX cabeçalho strings.h:-) ver opengroup.org
olibre
2
@AdamRosenfield 'pior' depende do contexto. Em segurança, às vezes o ponto principal de uma substituição é conseguir sobrescrever.
Este método é potencialmente inseguro e não portátil. std::tolowerfunciona apenas se o caractere for codificado em ASCII. Não existe tal garantia para std::string- portanto, pode ser um comportamento indefinido facilmente.
plasmacel
@plasmacel Em seguida, use uma função que funcione com outras codificações.
Brian Rodriguez
9
Para minhas necessidades básicas de comparação de cadeias sem distinção entre maiúsculas e minúsculas, prefiro não precisar usar uma biblioteca externa, nem quero uma classe de cadeia separada com características sem diferenciação de maiúsculas e minúsculas que sejam incompatíveis com todas as minhas outras strings.
Uma função simples com uma sobrecarga para char e outra para whar_t. Como não usa nada de fora do padrão, deve funcionar bem em qualquer plataforma.
A comparação de igualdade não considerará problemas como codificação de comprimento variável e normalização Unicode, mas o basic_string não tem suporte para o que eu saiba, e normalmente não é um problema.
Nos casos em que é necessária uma manipulação lexicográfica mais sofisticada do texto, você simplesmente precisa usar uma biblioteca de terceiros como o Boost, o que é esperado.
Você provavelmente poderia fazer essa função se o transformasse em um modelo e usasse basic_string <T> em vez de versões separadas de string / wstring?
uliwitness
2
Como o modelo de função única invocaria o toupper ou o towupper sem recorrer ao uso de especialização ou macros, uma sobrecarga de função parece uma implementação mais simples e apropriada do que qualquer um.
Neutrino
9
Curto e agradável. Nenhuma outra dependência, além do std C lib estendido .
strcasecmp(str1.c_str(), str2.c_str())==0
retorna true se str1e str2é igual.
strcasecmppode não existir, pode haver análogos stricmp, strcmpietc.
Código de exemplo:
#include<iostream>#include<string>#include<string.h>//For strcasecmp(). Also could be found in <mem.h>usingnamespace std;/// Simple wrapperinlinebool str_ignoreCase_cmp(std::string const& s1, std::string const& s2){if(s1.length()!= s2.length())returnfalse;// optimization since std::string holds length in variable.return strcasecmp(s1.c_str(), s2.c_str())==0;}/// Function object - comparatorstructStringCaseInsensetiveCompare{booloperator()(std::string const& s1, std::string const& s2){if(s1.length()!= s2.length())returnfalse;// optimization since std::string holds length in variable.return strcasecmp(s1.c_str(), s2.c_str())==0;}booloperator()(constchar*s1,constchar* s2){return strcasecmp(s1,s2)==0;}};/// Convert bool to stringinlinecharconst* bool2str(bool b){return b?"true":"false";}int main(){
cout<< bool2str(strcasecmp("asd","AsD")==0)<<endl;
cout<< bool2str(strcasecmp(string{"aasd"}.c_str(),string{"AasD"}.c_str())==0)<<endl;StringCaseInsensetiveCompare cmp;
cout<< bool2str(cmp("A","a"))<<endl;
cout<< bool2str(cmp(string{"Aaaa"},string{"aaaA"}))<<endl;
cout<< bool2str(str_ignoreCase_cmp(string{"Aaaa"},string{"aaaA"}))<<endl;return0;}
Supondo que você esteja procurando um método e não uma função mágica que já exista, francamente não há maneira melhor. Todos nós poderíamos escrever trechos de código com truques inteligentes para conjuntos de caracteres limitados, mas no final do dia, em algum momento, você precisa converter os caracteres.
A melhor abordagem para essa conversão é fazer isso antes da comparação. Isso permite uma grande flexibilidade quando se trata de esquemas de codificação, dos quais o seu operador de comparação real deve desconhecer.
É claro que você pode "ocultar" essa conversão atrás de sua própria função ou classe de string, mas ainda precisará converter as strings antes da comparação.
Eu escrevi uma versão sem distinção entre maiúsculas e minúsculas de char_traits para uso com std :: basic_string, a fim de gerar uma std :: string que não faz distinção entre maiúsculas e minúsculas ao fazer comparações, pesquisas etc. usando as funções integradas std :: basic_string.
Então, em outras palavras, eu queria fazer algo assim.
std::string a ="Hello, World!";
std::string b ="hello, world!";
assert( a == b );
... que std :: string não pode manipular. Aqui está o uso dos meus novos char_traits:
std::istring a ="Hello, World!";
std::istring b ="hello, world!";
assert( a == b );
... e aqui está a implementação:
/* ---
Case-Insensitive char_traits for std::string's
Use:
To declare a std::string which preserves case but ignores case in comparisons & search,
use the following syntax:
std::basic_string<char, char_traits_nocase<char> > noCaseString;
A typedef is declared below which simplifies this use for chars:
typedef std::basic_string<char, char_traits_nocase<char> > istring;
--- */template<class C>struct char_traits_nocase :public std::char_traits<C>{staticbool eq(const C& c1,const C& c2 ){return::toupper(c1)==::toupper(c2);}staticbool lt(const C& c1,const C& c2 ){return::toupper(c1)<::toupper(c2);}staticint compare(const C* s1,const C* s2,size_t N ){return _strnicmp(s1, s2, N);}staticconstchar* find(const C* s,size_t N,const C& a ){for(size_t i=0; i<N ;++i ){if(::toupper(s[i])==::toupper(a))return s+i ;}return0;}staticbool eq_int_type(const int_type& c1,const int_type& c2 ){return::toupper(c1)==::toupper(c2);}};template<>struct char_traits_nocase<wchar_t>:public std::char_traits<wchar_t>{staticbool eq(constwchar_t& c1,constwchar_t& c2 ){return::towupper(c1)==::towupper(c2);}staticbool lt(constwchar_t& c1,constwchar_t& c2 ){return::towupper(c1)<::towupper(c2);}staticint compare(constwchar_t* s1,constwchar_t* s2,size_t N ){return _wcsnicmp(s1, s2, N);}staticconstwchar_t* find(constwchar_t* s,size_t N,constwchar_t& a ){for(size_t i=0; i<N ;++i ){if(::towupper(s[i])==::towupper(a))return s+i ;}return0;}staticbool eq_int_type(const int_type& c1,const int_type& c2 ){return::towupper(c1)==::towupper(c2);}};typedef std::basic_string<char, char_traits_nocase<char>> istring;typedef std::basic_string<wchar_t, char_traits_nocase<wchar_t>> iwstring;
Isso funciona para caracteres regulares, mas não funciona para todo o Unicode, pois a captitalização não é necessariamente bidirecional (há um bom exemplo em grego envolvendo sigma que não me lembro agora; algo como ele tem duas letras maiúsculas e uma minúscula , e você não pode obter uma comparação de qualquer forma adequada)
coppro
11
Essa é realmente a maneira errada de fazer isso. A distinção entre maiúsculas e minúsculas não deve ser uma propriedade das próprias strings. O que acontece quando o mesmo objeto de string precisa de comparações que diferenciam maiúsculas e minúsculas de maiúsculas e minúsculas?
Ferruccio
Se a distinção entre maiúsculas e minúsculas não for apropriada para "fazer parte" da cadeia, a função find () também não será. O que, para você, pode ser verdade, e tudo bem. Na IMO, o melhor de C ++ é que ele não impõe um paradigma específico ao programador. É o que você quer / precisa que seja.
John Dibling
Na verdade, acho que a maioria dos guru de C ++ (como os do comitê de padrões) concorda que foi um erro colocar find () em std :: basic_string <> junto com muitas outras coisas que poderiam igualmente ser colocadas em funções livres. Além disso, existem alguns problemas em colocá-lo no tipo.
Andreas Magnusson
Como outros já apontaram, há duas coisas principais erradas nessa solução (ironicamente, uma é a interface e a outra é a implementação ;-)).
Konrad Rudolph
4
Eu tive uma boa experiência usando os componentes internacionais para bibliotecas Unicode - eles são extremamente poderosos e fornecem métodos para conversão, suporte de localidade, renderização de data e hora, mapeamento de caso (que você não parece querer) e agrupamento , que inclui comparação sem distinção entre maiúsculas e minúsculas (e mais). Eu usei apenas a versão C ++ das bibliotecas, mas elas parecem ter uma versão Java também.
Existem métodos para executar comparações normalizadas, como referido por @Coincoin, e podem até explicar a localidade - por exemplo (e este é um exemplo de classificação, não estritamente igualitário), tradicionalmente em espanhol (na Espanha), a combinação de letras "ll" classifica entre "l" e "m", então "lz" <"ll" <"ma".
Basta usar strcmp()para comparação entre maiúsculas e minúsculas e / strcmpi()ou sem stricmp()distinção entre maiúsculas e minúsculas. Que estão ambos no arquivo de cabeçalho<string.h>
formato:
int strcmp(constchar*,constchar*);//for case sensitiveint strcmpi(constchar*,constchar*);//for case insensitive
Uso:
string a="apple",b="ApPlE",c="ball";if(strcmpi(a.c_str(),b.c_str())==0)//(if it is a match it will return 0)
cout<<a<<" and "<<b<<" are the same"<<"\n";if(strcmpi(a.c_str(),b.c_str()<0)
cout<<a[0]<<" comes before ball "<<b[0]<<", so "<<a<<" comes before "<<b;
Voto negativo, porque essa dificilmente é uma maneira C ++ de fazer as coisas.
Thomas Daugaard 30/07
Esta é a convenção c ++ na minha universidade, mas eu vou manter isso em mente ao postar aqui
reubenjohn
4
stricmp é uma extensão da Microsoft AFAIK. O BSD parece ter strcasecmp ().
uliwitness
3
Tarde para a festa, mas aqui está uma variante que usa std::localee, portanto, manipula corretamente o turco:
auto tolower = std::bind1st(
std::mem_fun(&std::ctype<char>::tolower),&std::use_facet<std::ctype<char>>(
std::locale()));
fornece um functor que usa o código do idioma ativo para converter caracteres em minúsculas, que você pode usar via std::transformpara gerar cadeias de letras minúsculas:
std::string left ="fOo";
transform(left.begin(), left.end(), left.begin(), tolower);
Isso também funciona para wchar_tseqüências de caracteres baseadas.
Apenas uma observação sobre o método que você finalmente escolher, se esse método incluir o uso de strcmpalgumas respostas sugerem:
strcmpnão funciona com dados Unicode em geral. Em geral, ele nem funciona com codificações Unicode baseadas em bytes, como o utf-8, pois strcmpapenas faz comparações de bytes por byte e os pontos de código Unicode codificados no utf-8 podem levar mais de 1 byte. O único caso Unicode específico que strcmplida corretamente é quando uma string codificada com uma codificação baseada em bytes contém apenas pontos de código abaixo de U + 00FF - a comparação de bytes por byte é suficiente.
A UTI é uma "biblioteca Unicode completa e portátil que acompanha de perto os padrões do setor". Para o problema específico da comparação de cadeias, o objeto Collation faz o que você deseja.
O Projeto Mozilla adotou a UTI para internacionalização no Firefox em meados de 2012; você pode acompanhar a discussão de engenharia, incluindo problemas de sistemas de construção e tamanho do arquivo de dados, aqui:
Parece que as soluções acima não estão usando o método compare e a implementação total novamente, então aqui está a minha solução e espero que funcione para você (está funcionando bem).
Se você não deseja usar a biblioteca Boost , aqui está a solução usando apenas o cabeçalho io padrão C ++.
#include<iostream>struct iequal
{booloperator()(int c1,int c2)const{// case insensitive comparison of two characters.return std::toupper(c1)== std::toupper(c2);}};bool iequals(const std::string& str1,const std::string& str2){// use std::equal() to compare range of characters using the functor above.return std::equal(str1.begin(), str1.end(), str2.begin(), iequal());}int main(void){
std::string str_1 ="HELLO";
std::string str_2 ="hello";if(iequals(str_1,str_2)){
std::cout<<"String are equal"<<std::endl;}else{
std::cout<<"String are not equal"<<std::endl;}return0;}
Acredito que std :: toupper esteja em #include <cctype>, talvez seja necessário incluí-lo.
David Ledger
Se você usar uma versão global como esta :: toupper, talvez não seja necessário incluir <ctype> porque existem duas versões c version e c ++ version com localidade, eu acho. Tão melhor usar a versão global ":: toupper ()"
HaSeeB MiR
esta solução falha quando uma das cordas está vazia: "" - ele retorna true, nesse caso, quando deve retornar falso
ekkis
0
Se você precisar comparar uma string de origem com mais frequência com outras strings, uma solução elegante é usar regex.
std::wstring first = L"Test";
std::wstring second = L"TEST";
std::wregex pattern(first, std::wregex::icase);bool isEqual = std::regex_match(second, pattern);
Tentei este erro de compilação: error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Deqing 15/05
péssima ideia. É a pior solução.
Behrouz.M
Esta não é uma boa solução, mas mesmo se você queria usá-lo, você precisa de um L na frente de seus constantes WideString, por exemplo L "TEST"
celticminstrel
Seria bom se alguém pudesse explicar por que é a pior solução. Devido a problemas de desempenho? Criar a regex é caro, mas depois a comparação deve ser muito rápida.
smibe
é utilizável e portátil, o principal problema é que primeiro não pode conter nenhum caractere usado pelo regex. Não pode ser usado como uma comparação geral de cadeias por causa disso. Também será mais lento, há uma bandeira para fazê-lo funcionar da maneira que o smibe diz, mas ainda não pode ser usado como uma função geral.
Ben Ben
0
Uma maneira simples de comparar duas strings em c ++ (testado para windows) é usando _stricmp
// Case insensitive (could use equivalent _stricmp)
result = _stricmp( string1, string2 );
Se você deseja usar com std :: string, um exemplo:
std::string s1 = string("Hello");if( _stricmp(s1.c_str(),"HELLO")==0)
std::cout <<"The string are equals.";
bool insensitive_c_compare(char A,char B){staticchar mid_c =('Z'+'a')/2+'Z';staticchar up2lo ='A'-'a';/// the offset between upper and lowersif('a'>= A and A >='z'or'A'>= A and'Z'>= A)if('a'>= B and B >='z'or'A'>= B and'Z'>= B)/// check that the character is infact a letter/// (trying to turn a 3 into an E would not be pretty!){if(A > mid_c and B > mid_c or A < mid_c and B < mid_c){return A == B;}else{if(A > mid_c)
A = A -'a'+'A';if(B > mid_c)/// convert all uppercase letters to a lowercase ones
B = B -'a'+'A';/// this could be changed to B = B + up2lo;return A == B;}}}
isso provavelmente poderia se tornar muito mais eficiente, mas aqui está uma versão volumosa com todos os seus bits vazios.
não é tão portátil, mas funciona bem com o que estiver no meu computador (não faço ideia, sou de figuras, não de palavras)
Este não é o suporte Unicode, que é o que a pergunta foi feita.
Behrouz.M
Isso não suporta conjuntos de caracteres diferentes do inglês.
Robert Andrzejuk 29/04
-3
Uma maneira fácil de comparar seqüências de caracteres que são apenas diferentes por caracteres minúsculos e maiúsculos é fazer uma comparação ascii. Todas as letras maiúsculas e minúsculas diferem 32 bits na tabela ascii, usando essas informações, temos as seguintes ...
for(int i =0; i < string2.length(); i++){if(string1[i]== string2[i]||int(string1[i])==int(string2[j])+32||int(string1[i])==int(string2[i])-32){
count++;continue;}else{break;}if(count == string2.length()){//then we have a match}}
std::stricmp
. Caso contrário, leia o que Herb tem a dizer .strcasecmp
não faz parte do padrão e está ausente em pelo menos um compilador comum.Respostas:
O Boost inclui um algoritmo útil para isso:
fonte
Aproveite o padrão
char_traits
. Lembre-se de que astd::string
é de fato um typedef parastd::basic_string<char>
, ou mais explicitamentestd::basic_string<char, std::char_traits<char> >
,. Ochar_traits
tipo descreve como os caracteres são comparados, como eles copiam, como são convertidos etc. Tudo o que você precisa fazer é digitar uma nova sequência de caracteresbasic_string
e fornecer a ela seu próprio costumechar_traits
que compara maiúsculas e minúsculas.Os detalhes estão no Guru da Semana número 29 .
fonte
typedef std::basic_string<char, ci_char_traits<char> > istring
nãotypedef std::basic_string<char, std::char_traits<char> > string
.O problema com o impulso é que você precisa se conectar e depender do impulso. Não é fácil em alguns casos (por exemplo, android).
E usar char_traits significa tudo suas comparações não maiúsculas de minúsculas, o que geralmente não é o que você deseja.
Isso deve ser suficiente. Deve ser razoavelmente eficiente. Não lida com unicode ou qualquer coisa.
Atualização: versão bônus do C ++ 14 (
#include <algorithm>
):fonte
Se você estiver em um sistema POSIX, poderá usar o strcasecmp . Essa função não faz parte do padrão C, no entanto, nem está disponível no Windows. Isso fará uma comparação sem distinção entre maiúsculas e minúsculas em caracteres de 8 bits, desde que o código do idioma seja POSIX. Se o código do idioma não for POSIX, os resultados serão indefinidos (portanto, pode ser uma comparação localizada ou não). Um equivalente de caracteres largos não está disponível.
Caso contrário, um grande número de implementações históricas da biblioteca C possui as funções stricmp () e strnicmp (). O Visual C ++ no Windows renomeou todos esses itens, com um sublinhado como prefixo, porque eles não fazem parte do padrão ANSI; nesse sistema, eles são chamados _stricmp ou _strnicmp . Algumas bibliotecas também podem ter funções equivalentes a caracteres largos ou multibyte (normalmente denominadas, por exemplo, wcsicmp, mbcsicmp e assim por diante).
C e C ++ ignoram amplamente os problemas de internacionalização, portanto não há uma boa solução para esse problema, exceto o uso de uma biblioteca de terceiros. Confira IBM ICU (Componentes Internacionais para Unicode) se você precisar de uma biblioteca robusta para C / C ++. A UTI é para os sistemas Windows e Unix.
fonte
Você está falando de uma comparação sem distinção entre maiúsculas e minúsculas ou uma comparação Unicode normalizada completa?
Uma comparação idiota não encontrará cadeias que podem ser iguais, mas não são binárias iguais.
Exemplo:
São todos equivalentes, mas eles também têm diferentes representações binárias.
Dito isto, a Normalização Unicode deve ser uma leitura obrigatória, especialmente se você planeja dar suporte ao Hangul, Thaï e outros idiomas asiáticos.
Além disso, a IBM praticamente patenteou os algoritmos Unicode mais otimizados e os disponibilizou publicamente. Eles também mantêm uma implementação: IBM ICU
fonte
boost :: iequals não é compatível com utf-8 no caso de string. Você pode usar boost :: locale .
fonte
Meu primeiro pensamento para uma versão não-unicode foi fazer algo assim:
fonte
Você pode usar
strcasecmp
no Unix oustricmp
no Windows.Uma coisa que não foi mencionada até agora é que, se você estiver usando strings stl com esses métodos, é útil comparar primeiro o comprimento das duas strings, pois essas informações já estão disponíveis para você na classe de strings. Isso poderia impedir a comparação cara de uma string, se as duas strings que você está comparando não tiverem o mesmo comprimento em primeiro lugar.
fonte
Funções de seqüência de caracteres do Visual C ++ com suporte a unicode: http://msdn.microsoft.com/en-us/library/cc194799.aspx
o que você provavelmente está procurando é
_wcsnicmp
fonte
Estou tentando reunir uma boa resposta de todas as postagens, então me ajude a editar isso:
Aqui está um método para fazer isso, embora ele transforme as seqüências de caracteres e não seja compatível com Unicode, ele deve ser portátil, o que é uma vantagem:
Pelo que li, isso é mais portátil que o stricmp () porque o stricmp () não faz parte da biblioteca std, mas é implementado apenas pela maioria dos fornecedores de compiladores.
Para obter uma implementação realmente compatível com Unicode, parece que você deve sair da biblioteca std. Uma boa biblioteca de terceiros é o IBM ICU (International Components for Unicode)
O boost :: iequals também fornece um utilitário bastante bom para fazer esse tipo de comparação.
fonte
transform
toda a cadeia antes de comparaçãoVocê pode usar o código acima no C ++ 14 se não estiver em posição de usar o boost. Você tem que usar
std::towlower
para caracteres largos.fonte
str1.size() == str2.size() &&
para a frente para que não saia dos limites quando str2 é um prefixo de str1.A biblioteca Boost.String possui muitos algoritmos para fazer comparações sem distinção entre maiúsculas e minúsculas e assim por diante.
Você pode implementar o seu próprio, mas por que se preocupar quando isso já foi feito?
fonte
FYI
strcmp()
estricmp()
são vulneráveis ao estouro de buffer, pois apenas processam até atingir um terminador nulo. É mais seguro de usar_strncmp()
e_strnicmp()
.fonte
stricmp()
estrnicmp()
não fazem parte do padrão POSIX :-( No entanto, você pode encontrarstrcasecmp()
,strcasecmp_l()
,strncasecmp()
estrncasecmp_l()
em POSIX cabeçalhostrings.h
:-) ver opengroup.orgVeja
std::lexicographical_compare
:Demo
fonte
std::tolower
funciona apenas se o caractere for codificado em ASCII. Não existe tal garantia parastd::string
- portanto, pode ser um comportamento indefinido facilmente.Para minhas necessidades básicas de comparação de cadeias sem distinção entre maiúsculas e minúsculas, prefiro não precisar usar uma biblioteca externa, nem quero uma classe de cadeia separada com características sem diferenciação de maiúsculas e minúsculas que sejam incompatíveis com todas as minhas outras strings.
Então, o que eu criei é o seguinte:
Uma função simples com uma sobrecarga para char e outra para whar_t. Como não usa nada de fora do padrão, deve funcionar bem em qualquer plataforma.
A comparação de igualdade não considerará problemas como codificação de comprimento variável e normalização Unicode, mas o basic_string não tem suporte para o que eu saiba, e normalmente não é um problema.
Nos casos em que é necessária uma manipulação lexicográfica mais sofisticada do texto, você simplesmente precisa usar uma biblioteca de terceiros como o Boost, o que é esperado.
fonte
Curto e agradável. Nenhuma outra dependência, além do std C lib estendido .
retorna true se
str1
estr2
é igual.strcasecmp
pode não existir, pode haver análogosstricmp
,strcmpi
etc.Código de exemplo:
Resultado:
fonte
stricmp
,strcmpi
,strcasecmp
, Etc. Obrigado. mensagem editada.cout << boolalpha
vez do meubool2str
porque ele converte implicitamente bool em chars para fluxo.Isso sem o uso do Boost pode ser feito com o ponteiro da string C
c_str()
e usandostrcasecmp
:fonte
Supondo que você esteja procurando um método e não uma função mágica que já exista, francamente não há maneira melhor. Todos nós poderíamos escrever trechos de código com truques inteligentes para conjuntos de caracteres limitados, mas no final do dia, em algum momento, você precisa converter os caracteres.
A melhor abordagem para essa conversão é fazer isso antes da comparação. Isso permite uma grande flexibilidade quando se trata de esquemas de codificação, dos quais o seu operador de comparação real deve desconhecer.
É claro que você pode "ocultar" essa conversão atrás de sua própria função ou classe de string, mas ainda precisará converter as strings antes da comparação.
fonte
Eu escrevi uma versão sem distinção entre maiúsculas e minúsculas de char_traits para uso com std :: basic_string, a fim de gerar uma std :: string que não faz distinção entre maiúsculas e minúsculas ao fazer comparações, pesquisas etc. usando as funções integradas std :: basic_string.
Então, em outras palavras, eu queria fazer algo assim.
... que std :: string não pode manipular. Aqui está o uso dos meus novos char_traits:
... e aqui está a implementação:
fonte
Eu tive uma boa experiência usando os componentes internacionais para bibliotecas Unicode - eles são extremamente poderosos e fornecem métodos para conversão, suporte de localidade, renderização de data e hora, mapeamento de caso (que você não parece querer) e agrupamento , que inclui comparação sem distinção entre maiúsculas e minúsculas (e mais). Eu usei apenas a versão C ++ das bibliotecas, mas elas parecem ter uma versão Java também.
Existem métodos para executar comparações normalizadas, como referido por @Coincoin, e podem até explicar a localidade - por exemplo (e este é um exemplo de classificação, não estritamente igualitário), tradicionalmente em espanhol (na Espanha), a combinação de letras "ll" classifica entre "l" e "m", então "lz" <"ll" <"ma".
fonte
Basta usar
strcmp()
para comparação entre maiúsculas e minúsculas e /strcmpi()
ou semstricmp()
distinção entre maiúsculas e minúsculas. Que estão ambos no arquivo de cabeçalho<string.h>
formato:
Uso:
Resultado
Apple e ApPlE são os mesmos
a vem antes de b, então a maçã vem antes da bola
fonte
Tarde para a festa, mas aqui está uma variante que usa
std::locale
e, portanto, manipula corretamente o turco:fornece um functor que usa o código do idioma ativo para converter caracteres em minúsculas, que você pode usar via
std::transform
para gerar cadeias de letras minúsculas:Isso também funciona para
wchar_t
seqüências de caracteres baseadas.fonte
Apenas uma observação sobre o método que você finalmente escolher, se esse método incluir o uso de
strcmp
algumas respostas sugerem:strcmp
não funciona com dados Unicode em geral. Em geral, ele nem funciona com codificações Unicode baseadas em bytes, como o utf-8, poisstrcmp
apenas faz comparações de bytes por byte e os pontos de código Unicode codificados no utf-8 podem levar mais de 1 byte. O único caso Unicode específico questrcmp
lida corretamente é quando uma string codificada com uma codificação baseada em bytes contém apenas pontos de código abaixo de U + 00FF - a comparação de bytes por byte é suficiente.fonte
Desde o início de 2013, o projeto de UTI, mantido pela IBM, é uma resposta muito boa para isso.
http://site.icu-project.org/
A UTI é uma "biblioteca Unicode completa e portátil que acompanha de perto os padrões do setor". Para o problema específico da comparação de cadeias, o objeto Collation faz o que você deseja.
O Projeto Mozilla adotou a UTI para internacionalização no Firefox em meados de 2012; você pode acompanhar a discussão de engenharia, incluindo problemas de sistemas de construção e tamanho do arquivo de dados, aqui:
fonte
Parece que as soluções acima não estão usando o método compare e a implementação total novamente, então aqui está a minha solução e espero que funcione para você (está funcionando bem).
fonte
Se você não deseja usar a biblioteca Boost , aqui está a solução usando apenas o cabeçalho io padrão C ++.
fonte
Se você precisar comparar uma string de origem com mais frequência com outras strings, uma solução elegante é usar regex.
fonte
error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Uma maneira simples de comparar duas strings em c ++ (testado para windows) é usando _stricmp
Se você deseja usar com std :: string, um exemplo:
Para mais informações aqui: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx
fonte
isso provavelmente poderia se tornar muito mais eficiente, mas aqui está uma versão volumosa com todos os seus bits vazios.
não é tão portátil, mas funciona bem com o que estiver no meu computador (não faço ideia, sou de figuras, não de palavras)
fonte
Uma maneira fácil de comparar seqüências de caracteres que são apenas diferentes por caracteres minúsculos e maiúsculos é fazer uma comparação ascii. Todas as letras maiúsculas e minúsculas diferem 32 bits na tabela ascii, usando essas informações, temos as seguintes ...
fonte