Comparación de cadenas sin distinción entre mayúsculas y minúsculas en C ++ [cerrado]
373
¿Cuál es la mejor manera de hacer una comparación de cadenas sin distinción entre mayúsculas y minúsculas en C ++ sin transformar una cadena en mayúsculas o minúsculas?
Indique si los métodos son compatibles con Unicode y qué tan portátiles son.
@ [Adam] (# 11679): Si bien esta variante es buena en términos de usabilidad, es mala en términos de rendimiento porque crea copias innecesarias. Podría pasar por alto algo, pero creo que la mejor manera (no Unicode) es usarlo std::stricmp. De lo contrario, lea lo que Herb tiene que decir .
Konrad Rudolph el
En c, uno generalmente se vio forzado a tocar toda la cuerda y luego comparar de esa manera, o hacer su propia comparación: P
Michael Dorgan
una pregunta posterior tiene una respuesta más simple: strcasecmp (al menos para los compiladores BSD y POSIX) stackoverflow.com/questions/9182912/…
Móż
@ Mσᶎ esta pregunta también tiene esa respuesta, con la advertencia importante que strcasecmpno es parte del estándar y que falta en al menos un compilador común.
Mark Ransom
Respuestas:
318
Boost incluye un algoritmo útil para esto:
#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}
No, porque UTF-8 permite cadenas idénticas a ser codificados con diferentes códigos binarios, debido a los acentos, cosechadoras, problemas bidi, etc.
vy32
10
@ vy32 ¡Eso es absolutamente incorrecto! Las combinaciones UTF-8 son mutuamente excluyentes. Siempre debe usar la representación más corta posible, si no lo hace, es una secuencia UTF-8 malformada o un punto de código que debe tratarse con cuidado.
Wiz
48
@Wiz, está ignorando el problema de la normalización de cadenas Unicode. ñ puede representarse como una combinación ˜ seguida de una n, o con un carácter ñ. Debe usar la normalización de cadena Unicode antes de realizar la comparación. Por favor revise el Informe Técnico de Unicode # 15, unicode.org/reports/tr15
Aprovecha el estándar char_traits. Recordemos que una std::stringes en realidad un typedef para std::basic_string<char>, o más explícitamente, std::basic_string<char, std::char_traits<char> >. El char_traitstipo describe cómo se comparan los personajes, cómo se copian, cómo se emiten, etc. Todo lo que necesita hacer es escribir una nueva cadena basic_string, y proporcionarle su propia costumbre char_traitsque compare mayúsculas y minúsculas.
Hasta donde sé por mi propia experimentación, esto hace que su nuevo tipo de cadena sea incompatible con std :: string.
Zan Lynx
8
Por supuesto que sí, por su propio bien. Una cadena que no distingue entre mayúsculas y minúsculas es otra cosa: typedef std::basic_string<char, ci_char_traits<char> > istringno typedef std::basic_string<char, std::char_traits<char> > string.
Andreas Spindler
232
"Todo lo que necesitas hacer ..."
Tim MB
3
@Nathan probablemente use un compilador que pueda realizar CSE básico en el código ...
The Paramagnetic Croissant
17
Cualquier construcción de lenguaje que fuerce tal locura en este caso trivial debería y puede ser abandonada sin remordimientos.
Erik Aronesty
86
El problema con el impulso es que debe vincularse y depender del impulso. No es fácil en algunos casos (por ejemplo, Android).
Y usar char_traits significa que todas sus comparaciones no distinguen entre mayúsculas y minúsculas, lo que generalmente no es lo que desea.
Esto debería ser suficiente. Debería ser razonablemente eficiente. Sin embargo, no maneja unicode ni nada.
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;}
Actualización: Bonus C ++ 14 versión ( #include <algorithm>):
En realidad, la biblioteca de cadenas de impulso es una biblioteca de solo encabezado, por lo que no es necesario vincular a nada. Además, puede usar la utilidad 'bcp' de boost para copiar solo los encabezados de cadena en su árbol de origen, por lo que no necesita requerir la biblioteca de impulso completa.
Gretchen
Ah, no sabía sobre bcp, parece realmente útil. Gracias por la info!
Timmmm
99
Es bueno saber una versión simple y sin dependencia de impulso.
Deqing
2
@Anna La biblioteca de texto de impulso necesita ser construida y enlazada. Utiliza IBM ICU.
Behrouz.M
También disponible con C ++ 11
marciano
58
Si está en un sistema POSIX, puede usar strcasecmp . Sin embargo, esta función no forma parte del estándar C ni está disponible en Windows. Esto realizará una comparación que no distingue entre mayúsculas y minúsculas en caracteres de 8 bits, siempre que el entorno local sea POSIX. Si la configuración regional no es POSIX, los resultados no están definidos (por lo que podría hacer una comparación localizada o no). Un equivalente de caracteres anchos no está disponible.
De lo contrario, una gran cantidad de implementaciones históricas de la biblioteca C tienen las funciones stricmp () y strnicmp (). Visual C ++ en Windows los renombró a todos al ponerles un guión bajo porque no forman parte del estándar ANSI, por lo que en ese sistema se llaman _stricmp o _strnicmp . Algunas bibliotecas también pueden tener funciones equivalentes de caracteres anchos o multibyte (normalmente denominadas, por ejemplo, wcsicmp, mbcsicmp, etc.).
C y C ++ ignoran en gran medida los problemas de internacionalización, por lo que no hay una buena solución para este problema, excepto el uso de una biblioteca de terceros. Consulte IBM ICU (Componentes internacionales para Unicode) si necesita una biblioteca robusta para C / C ++. ICU es para sistemas Windows y Unix.
¿Estás hablando de una comparación insensible a mayúsculas y minúsculas o una comparación Unicode completamente normalizada?
Una comparación tonta no encontrará cadenas que puedan ser iguales pero que no sean binarias iguales.
Ejemplo:
U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A)+ U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).
Todos son equivalentes pero también tienen diferentes representaciones binarias.
Dicho esto, la normalización Unicode debería ser una lectura obligatoria, especialmente si planea admitir Hangul, tailandés y otros idiomas asiáticos.
Además, IBM prácticamente patentó los algoritmos Unicode más optimizados y los puso a disposición del público. También mantienen una implementación: IBM ICU
Principal: ignora los acentos y las mayúsculas y minúsculas, solo compara letras de base. Por ejemplo, "fachada" y "Fachada" son lo mismo.
Secundario: ignore las mayúsculas y minúsculas, pero tenga en cuenta los acentos. "fachada" y "fachada" son diferentes pero "Fachada" y "fachada" son iguales.
Terciario: considere tanto el caso como los acentos: "Fachada" y "fachada" son diferentes. Ignorar la puntuación.
Cuaternario: considere todos los casos, acentos y puntuación. Las palabras deben ser idénticas en términos de representación Unicode.
Idéntico: como cuaternario, pero también compara puntos de código.
Una cosa que no se ha mencionado hasta ahora es que si está utilizando cadenas stl con estos métodos, es útil comparar primero la longitud de las dos cadenas, ya que esta información ya está disponible en la clase de cadena. Esto podría evitar hacer la costosa comparación de cadenas si las dos cadenas que está comparando ni siquiera tienen la misma longitud en primer lugar.
Dado que determinar la longitud de una cadena consiste en iterar sobre cada carácter de la cadena y compararlo con 0, ¿existe realmente tanta diferencia entre eso y solo comparar las cadenas de inmediato? Supongo que obtienes una mejor ubicación de memoria en el caso en que ambas cadenas no coinciden, pero probablemente casi 2 veces el tiempo de ejecución en caso de una coincidencia.
Es un hecho pequeño y divertido, pero tiene poco que ver aquí. strcasecmp () y stricmp () toman cadenas C sin decorar, por lo que no hay std :: string involucrado.
uliwitness
3
Estos métodos devolverán -1 si compara "a" vs "ab". Las longitudes son diferentes pero "a" viene antes que "ab". Entonces, simplemente comparar las longitudes no es factible si la persona que llama se preocupa por ordenar.
Por lo que he leído, esto es más portátil que stricmp () porque stricmp () no es, de hecho, parte de la biblioteca estándar, sino que solo es implementado por la mayoría de los proveedores de compiladores.
Para obtener una implementación verdaderamente amigable con Unicode, parece que debe salir de la biblioteca estándar. Una buena biblioteca de terceros es IBM ICU (Componentes internacionales para Unicode)
También boost :: iequals proporciona una utilidad bastante buena para hacer este tipo de comparación.
"... ¿por qué molestarse cuando ya está hecho?" - ¿Qué pasa si no estás usando Boost? El OP no tenía la etiqueta con la pregunta.
jww
11
Para su información, strcmp()y stricmp()son vulnerables al desbordamiento del búfer, ya que solo se procesan hasta que llegan a un terminador nulo. Es más seguro de usar _strncmp()y _strnicmp().
Es cierto, aunque sobre-LEER un buffer es significativamente menos peligroso que sobreescribir un buffer.
Adam Rosenfield
44
stricmp()y strnicmp()no es parte del estándar POSIX :-( Sin embargo, usted puede encontrar strcasecmp(), strcasecmp_l(), strncasecmp()y strncasecmp_l()en la cabecera POSIX strings.h:-) ve opengroup.org
olibre
2
@AdamRosenfield 'peor' depende del contexto. En seguridad, a veces el objetivo de una sobrescritura es llegar a leer demasiado.
Este método es potencialmente inseguro y no portátil. std::tolowerfunciona solo si el carácter está codificado en ASCII. No existe tal garantía, por std::stringlo que puede ser un comportamiento indefinido fácilmente.
plasmacel
@plasmacel Luego use una función que funcione con otras codificaciones.
Brian Rodriguez
9
Para mis necesidades básicas de comparación de cadenas que no distinguen entre mayúsculas y minúsculas, prefiero no tener que usar una biblioteca externa, ni quiero una clase de cadena separada con rasgos que no distingan entre mayúsculas y minúsculas que sea incompatible con todas mis otras cadenas.
Una función simple con una sobrecarga para char y otra para whar_t. No utiliza nada no estándar, por lo que debería estar bien en cualquier plataforma.
La comparación de igualdad no considerará problemas como la codificación de longitud variable y la normalización Unicode, pero basic_string no tiene soporte para eso de lo que soy consciente de todos modos y normalmente no es un problema.
En los casos en que se requiera una manipulación lexicográfica más sofisticada del texto, simplemente debe usar una biblioteca de terceros como Boost, lo cual es de esperar.
¿Probablemente podría hacer esa función si la hiciera una plantilla y utilizara basic_string <T> en lugar de versiones separadas de string / wstring?
uliwitness
2
¿Cómo invocaría la plantilla de función única ya sea touperper o towupper sin recurrir al uso de especialización o macros, una sobrecarga de funciones parece una implementación más simple y más apropiada que cualquiera de las dos?
Neutrino
9
Corto y agradable. No hay otras dependencias, que la extensión estándar de C lib.
strcasecmp(str1.c_str(), str2.c_str())==0
devuelve verdadero si str1y str2son iguales.
strcasecmppuede no existir, podría ser análogos stricmp, strcmpietc.
Código de ejemplo:
#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;}
Suponiendo que está buscando un método y no una función mágica que ya existe, francamente no hay mejor manera. Todos podríamos escribir fragmentos de código con trucos inteligentes para conjuntos de caracteres limitados, pero al final del día, en algún momento, debe convertir los caracteres.
El mejor enfoque para esta conversión es hacerlo antes de la comparación. Esto le permite una gran flexibilidad cuando se trata de esquemas de codificación, que su operador de comparación real debe ignorar.
Por supuesto, puede 'ocultar' esta conversión detrás de su propia función de cadena o clase, pero aún necesita convertir las cadenas antes de la comparación.
Escribí una versión que distingue entre mayúsculas y minúsculas de char_traits para usar con std :: basic_string para generar una cadena std :: que no distingue entre mayúsculas y minúsculas al hacer comparaciones, búsquedas, etc. utilizando las funciones integradas std :: basic_string.
En otras palabras, quería hacer algo como esto.
std::string a ="Hello, World!";
std::string b ="hello, world!";
assert( a == b );
... que std :: string no puede manejar. Aquí está el uso de mis nuevos char_traits:
std::istring a ="Hello, World!";
std::istring b ="hello, world!";
assert( a == b );
... y aquí está la implementación:
/* ---
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;
Esto funciona para caracteres normales, pero no funcionará para todo Unicode, ya que la captura no es necesariamente bidireccional (hay un buen ejemplo en griego que implica sigma que no puedo recordar en este momento; algo así como tiene dos minúsculas y una mayúscula , y no puede obtener una comparación adecuada de ninguna manera)
coppro
1
Esa es realmente la forma incorrecta de hacerlo. La distinción entre mayúsculas y minúsculas no debería ser una propiedad de las cadenas en sí. ¿Qué sucede cuando el mismo objeto de cadena necesita comparaciones sensibles a mayúsculas y minúsculas?
Ferruccio
Si la distinción entre mayúsculas y minúsculas no es apropiada para ser "parte de" la cadena, tampoco lo es la función find (). Lo cual, para ti, podría ser cierto, y eso está bien. En mi opinión, lo mejor de C ++ es que no impone un paradigma particular al programador. Es lo que quieres / necesitas que sea.
John Dibling el
En realidad, creo que la mayoría de los gurús de C ++ (como los del comité de estándares) están de acuerdo en que fue un error colocar find () en std :: basic_string <> junto con muchas otras cosas que también podrían colocarse funciones libres Además, hay algunos problemas para ponerlo en el tipo.
Andreas Magnusson el
Como otros han señalado, hay dos cosas principales que están mal con esta solución (irónicamente, una es la interfaz y la otra es la implementación ;-)).
Konrad Rudolph el
4
He tenido una buena experiencia en el uso de los componentes internacionales para bibliotecas Unicode : son extremadamente potentes y proporcionan métodos para la conversión, soporte de configuración regional, representación de fecha y hora, asignación de casos (que no parece querer) y cotejo , que incluye la comparación entre mayúsculas y minúsculas (y más). Solo he usado la versión C ++ de las bibliotecas, pero parece que también tienen una versión Java.
Existen métodos para realizar comparaciones normalizadas a las que se refiere @Coincoin, e incluso pueden tener en cuenta la configuración regional, por ejemplo (y este es un ejemplo de clasificación, no estrictamente de igualdad), tradicionalmente en español (en España), la combinación de letras "ll" clasifica entre "l" y "m", entonces "lz" <"ll" <"ma".
Solo utilícelo strcmp()para la comparación entre mayúsculas y minúsculas y / strcmpi()o stricmp()para mayúsculas y minúsculas. Que están en el archivo de encabezado<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;
Salida
apple y ApPlE son lo mismo
a viene antes que b, entonces la manzana viene antes que la pelota
Voto negativo porque esta no es una forma de hacer las cosas en C ++.
Thomas Daugaard
Esta es la convención de C ++ en mi universidad, pero lo tendré en cuenta cuando publique aquí
reubenjohn
44
stricmp es una extensión de Microsoft AFAIK. BSD parece tener strcasecmp () en su lugar.
testigo del
3
Tarde a la fiesta, pero aquí hay una variante que usa std::locale, y por lo tanto maneja correctamente el turco:
auto tolower = std::bind1st(
std::mem_fun(&std::ctype<char>::tolower),&std::use_facet<std::ctype<char>>(
std::locale()));
le ofrece un functor que usa la configuración regional activa para convertir caracteres en minúsculas, que luego puede usar a través de std::transformpara generar cadenas en minúsculas:
std::string left ="fOo";
transform(left.begin(), left.end(), left.begin(), tolower);
Esto también funciona para wchar_tcadenas basadas.
Solo una nota sobre el método que finalmente elija, si ese método incluye el uso de strcmpeso, algunas respuestas sugieren:
strcmpno funciona con datos Unicode en general. En general, ni siquiera funciona con codificaciones Unicode basadas en bytes, como utf-8, ya que strcmpsolo hace comparaciones byte por byte y los puntos de código Unicode codificados en utf-8 pueden tomar más de 1 byte. El único caso Unicode específico que strcmpse maneja correctamente es cuando una cadena codificada con una codificación basada en bytes contiene solo puntos de código por debajo de U + 00FF, entonces la comparación byte por byte es suficiente.
ICU es una "biblioteca Unicode completa y portátil que sigue de cerca los estándares de la industria". Para el problema específico de la comparación de cadenas, el objeto Collation hace lo que desea.
El Proyecto Mozilla adoptó la UCI para la internacionalización en Firefox a mediados de 2012; puede seguir la discusión de ingeniería, incluidos los problemas de los sistemas de compilación y el tamaño del archivo de datos, aquí:
Parece que las soluciones anteriores no están utilizando el método de comparación e implementando el total nuevamente, así que aquí está mi solución y espero que funcione para usted (está funcionando bien).
Si no desea usar la biblioteca Boost , aquí hay una solución para usar solo el encabezado io estándar de 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;}
Creo que std :: toupper está en #include <cctype>, es posible que deba incluirlo.
David Ledger
Si va a usar una versión global como esta :: toupper, entonces es posible que no necesite incluir <ctype> porque hay dos versiones versión c y versión c ++ con configuración regional, supongo. Así que mejor usar la versión global ":: toupper ()"
HaSeeB MiR
esta solución falla cuando una de las cadenas está vacía: "" - devuelve verdadero en ese caso cuando debería devolver falso
ekkis
0
Si tiene que comparar una cadena fuente con más frecuencia con otras cadenas, una solución elegante es 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);
Intenté esto pero error de compilación: error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Deqing
mala idea. Es la peor solución.
Behrouz.M
Esta no es una buena solución, pero incluso si desea usarla, necesita una L delante de sus constantes de cadena ancha, por ejemplo, L "TEST"
celticminstrel
Sería bueno si alguien pudiera explicar por qué es la peor solución. ¿Por problemas de rendimiento? Crear la expresión regular es costoso, pero luego la comparación debería ser realmente rápida.
smibe
es utilizable y portátil, el principal problema es que primero no puede contener ningún carácter que use regex. No se puede usar como una comparación general de cadenas debido a eso. También será más lento, hay una bandera para que funcione como dice smibe, pero aún no se puede usar como una función general.
Ben
0
Una manera simple de comparar dos cadenas en c ++ (probado para Windows) es usando _stricmp
// Case insensitive (could use equivalent _stricmp)
result = _stricmp( string1, string2 );
Si está buscando usar con std :: string, un ejemplo:
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;}}}
Esto probablemente podría hacerse mucho más eficiente, pero aquí hay una versión voluminosa con todos sus bits al descubierto.
no es tan portátil, pero funciona bien con lo que sea que esté en mi computadora (ni idea, soy de imágenes, no de palabras)
Este no es un soporte Unicode, que es lo que se hizo la pregunta.
Behrouz.M
Esto no admite juegos de caracteres que no estén en inglés.
Robert Andrzejuk
-3
Una manera fácil de comparar cadenas que solo son diferentes en minúsculas y mayúsculas es hacer una comparación ascii. Todas las letras mayúsculas y minúsculas difieren en 32 bits en la tabla ASCII, utilizando esta información tenemos lo siguiente ...
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
. De lo contrario, lea lo que Herb tiene que decir .strcasecmp
no es parte del estándar y que falta en al menos un compilador común.Respuestas:
Boost incluye un algoritmo útil para esto:
fuente
Aprovecha el estándar
char_traits
. Recordemos que unastd::string
es en realidad un typedef parastd::basic_string<char>
, o más explícitamente,std::basic_string<char, std::char_traits<char> >
. Elchar_traits
tipo describe cómo se comparan los personajes, cómo se copian, cómo se emiten, etc. Todo lo que necesita hacer es escribir una nueva cadenabasic_string
, y proporcionarle su propia costumbrechar_traits
que compare mayúsculas y minúsculas.Los detalles están en el Gurú de la semana número 29 .
fuente
typedef std::basic_string<char, ci_char_traits<char> > istring
notypedef std::basic_string<char, std::char_traits<char> > string
.El problema con el impulso es que debe vincularse y depender del impulso. No es fácil en algunos casos (por ejemplo, Android).
Y usar char_traits significa que todas sus comparaciones no distinguen entre mayúsculas y minúsculas, lo que generalmente no es lo que desea.
Esto debería ser suficiente. Debería ser razonablemente eficiente. Sin embargo, no maneja unicode ni nada.
Actualización: Bonus C ++ 14 versión (
#include <algorithm>
):fuente
Si está en un sistema POSIX, puede usar strcasecmp . Sin embargo, esta función no forma parte del estándar C ni está disponible en Windows. Esto realizará una comparación que no distingue entre mayúsculas y minúsculas en caracteres de 8 bits, siempre que el entorno local sea POSIX. Si la configuración regional no es POSIX, los resultados no están definidos (por lo que podría hacer una comparación localizada o no). Un equivalente de caracteres anchos no está disponible.
De lo contrario, una gran cantidad de implementaciones históricas de la biblioteca C tienen las funciones stricmp () y strnicmp (). Visual C ++ en Windows los renombró a todos al ponerles un guión bajo porque no forman parte del estándar ANSI, por lo que en ese sistema se llaman _stricmp o _strnicmp . Algunas bibliotecas también pueden tener funciones equivalentes de caracteres anchos o multibyte (normalmente denominadas, por ejemplo, wcsicmp, mbcsicmp, etc.).
C y C ++ ignoran en gran medida los problemas de internacionalización, por lo que no hay una buena solución para este problema, excepto el uso de una biblioteca de terceros. Consulte IBM ICU (Componentes internacionales para Unicode) si necesita una biblioteca robusta para C / C ++. ICU es para sistemas Windows y Unix.
fuente
¿Estás hablando de una comparación insensible a mayúsculas y minúsculas o una comparación Unicode completamente normalizada?
Una comparación tonta no encontrará cadenas que puedan ser iguales pero que no sean binarias iguales.
Ejemplo:
Todos son equivalentes pero también tienen diferentes representaciones binarias.
Dicho esto, la normalización Unicode debería ser una lectura obligatoria, especialmente si planea admitir Hangul, tailandés y otros idiomas asiáticos.
Además, IBM prácticamente patentó los algoritmos Unicode más optimizados y los puso a disposición del público. También mantienen una implementación: IBM ICU
fuente
boost :: iequals no es compatible con utf-8 en el caso de una cadena. Puede usar boost :: locale .
fuente
Mi primer pensamiento para una versión no Unicode fue hacer algo como esto:
fuente
Puede usar
strcasecmp
en Unix ostricmp
en Windows.Una cosa que no se ha mencionado hasta ahora es que si está utilizando cadenas stl con estos métodos, es útil comparar primero la longitud de las dos cadenas, ya que esta información ya está disponible en la clase de cadena. Esto podría evitar hacer la costosa comparación de cadenas si las dos cadenas que está comparando ni siquiera tienen la misma longitud en primer lugar.
fuente
Funciones de cadena de Visual C ++ que admiten unicode: http://msdn.microsoft.com/en-us/library/cc194799.aspx
el que probablemente estás buscando es
_wcsnicmp
fuente
Estoy tratando de improvisar una buena respuesta de todas las publicaciones, así que ayúdame a editar esto:
Aquí hay un método para hacerlo, aunque transforma las cadenas y no es compatible con Unicode, debería ser portátil, lo cual es una ventaja:
Por lo que he leído, esto es más portátil que stricmp () porque stricmp () no es, de hecho, parte de la biblioteca estándar, sino que solo es implementado por la mayoría de los proveedores de compiladores.
Para obtener una implementación verdaderamente amigable con Unicode, parece que debe salir de la biblioteca estándar. Una buena biblioteca de terceros es IBM ICU (Componentes internacionales para Unicode)
También boost :: iequals proporciona una utilidad bastante buena para hacer este tipo de comparación.
fuente
transform
toda la cadena antes de la comparaciónPuede usar el código anterior en C ++ 14 si no está en condiciones de usar boost. Tienes que usar
std::towlower
para caracteres anchos.fuente
str1.size() == str2.size() &&
al frente para que no se salga de los límites cuando str2 es un prefijo de str1.La biblioteca Boost.String tiene muchos algoritmos para hacer comparaciones que no distinguen entre mayúsculas y minúsculas, etc.
Podrías implementar el tuyo, pero ¿por qué molestarse cuando ya está hecho?
fuente
Para su información,
strcmp()
ystricmp()
son vulnerables al desbordamiento del búfer, ya que solo se procesan hasta que llegan a un terminador nulo. Es más seguro de usar_strncmp()
y_strnicmp()
.fuente
stricmp()
ystrnicmp()
no es parte del estándar POSIX :-( Sin embargo, usted puede encontrarstrcasecmp()
,strcasecmp_l()
,strncasecmp()
ystrncasecmp_l()
en la cabecera POSIXstrings.h
:-) ve opengroup.orgVer
std::lexicographical_compare
:Manifestación
fuente
std::tolower
funciona solo si el carácter está codificado en ASCII. No existe tal garantía, porstd::string
lo que puede ser un comportamiento indefinido fácilmente.Para mis necesidades básicas de comparación de cadenas que no distinguen entre mayúsculas y minúsculas, prefiero no tener que usar una biblioteca externa, ni quiero una clase de cadena separada con rasgos que no distingan entre mayúsculas y minúsculas que sea incompatible con todas mis otras cadenas.
Entonces, lo que se me ocurrió es esto:
Una función simple con una sobrecarga para char y otra para whar_t. No utiliza nada no estándar, por lo que debería estar bien en cualquier plataforma.
La comparación de igualdad no considerará problemas como la codificación de longitud variable y la normalización Unicode, pero basic_string no tiene soporte para eso de lo que soy consciente de todos modos y normalmente no es un problema.
En los casos en que se requiera una manipulación lexicográfica más sofisticada del texto, simplemente debe usar una biblioteca de terceros como Boost, lo cual es de esperar.
fuente
Corto y agradable. No hay otras dependencias, que la extensión estándar de C lib.
devuelve verdadero si
str1
ystr2
son iguales.strcasecmp
puede no existir, podría ser análogosstricmp
,strcmpi
etc.Código de ejemplo:
Salida:
fuente
stricmp
,strcmpi
,strcasecmp
, Etc Gracias. Mensaje editado.cout << boolalpha
lugar de mybool2str
porque implícitamente convierte bool a chars para stream.Hacer esto sin usar Boost se puede hacer obteniendo el puntero de cadena C con
c_str()
y usandostrcasecmp
:fuente
Suponiendo que está buscando un método y no una función mágica que ya existe, francamente no hay mejor manera. Todos podríamos escribir fragmentos de código con trucos inteligentes para conjuntos de caracteres limitados, pero al final del día, en algún momento, debe convertir los caracteres.
El mejor enfoque para esta conversión es hacerlo antes de la comparación. Esto le permite una gran flexibilidad cuando se trata de esquemas de codificación, que su operador de comparación real debe ignorar.
Por supuesto, puede 'ocultar' esta conversión detrás de su propia función de cadena o clase, pero aún necesita convertir las cadenas antes de la comparación.
fuente
Escribí una versión que distingue entre mayúsculas y minúsculas de char_traits para usar con std :: basic_string para generar una cadena std :: que no distingue entre mayúsculas y minúsculas al hacer comparaciones, búsquedas, etc. utilizando las funciones integradas std :: basic_string.
En otras palabras, quería hacer algo como esto.
... que std :: string no puede manejar. Aquí está el uso de mis nuevos char_traits:
... y aquí está la implementación:
fuente
He tenido una buena experiencia en el uso de los componentes internacionales para bibliotecas Unicode : son extremadamente potentes y proporcionan métodos para la conversión, soporte de configuración regional, representación de fecha y hora, asignación de casos (que no parece querer) y cotejo , que incluye la comparación entre mayúsculas y minúsculas (y más). Solo he usado la versión C ++ de las bibliotecas, pero parece que también tienen una versión Java.
Existen métodos para realizar comparaciones normalizadas a las que se refiere @Coincoin, e incluso pueden tener en cuenta la configuración regional, por ejemplo (y este es un ejemplo de clasificación, no estrictamente de igualdad), tradicionalmente en español (en España), la combinación de letras "ll" clasifica entre "l" y "m", entonces "lz" <"ll" <"ma".
fuente
Solo utilícelo
strcmp()
para la comparación entre mayúsculas y minúsculas y /strcmpi()
ostricmp()
para mayúsculas y minúsculas. Que están en el archivo de encabezado<string.h>
formato:
Uso:
Salida
apple y ApPlE son lo mismo
a viene antes que b, entonces la manzana viene antes que la pelota
fuente
Tarde a la fiesta, pero aquí hay una variante que usa
std::locale
, y por lo tanto maneja correctamente el turco:le ofrece un functor que usa la configuración regional activa para convertir caracteres en minúsculas, que luego puede usar a través de
std::transform
para generar cadenas en minúsculas:Esto también funciona para
wchar_t
cadenas basadas.fuente
Solo una nota sobre el método que finalmente elija, si ese método incluye el uso de
strcmp
eso, algunas respuestas sugieren:strcmp
no funciona con datos Unicode en general. En general, ni siquiera funciona con codificaciones Unicode basadas en bytes, como utf-8, ya questrcmp
solo hace comparaciones byte por byte y los puntos de código Unicode codificados en utf-8 pueden tomar más de 1 byte. El único caso Unicode específico questrcmp
se maneja correctamente es cuando una cadena codificada con una codificación basada en bytes contiene solo puntos de código por debajo de U + 00FF, entonces la comparación byte por byte es suficiente.fuente
A principios de 2013, el proyecto ICU, mantenido por IBM, es una respuesta bastante buena a esto.
http://site.icu-project.org/
ICU es una "biblioteca Unicode completa y portátil que sigue de cerca los estándares de la industria". Para el problema específico de la comparación de cadenas, el objeto Collation hace lo que desea.
El Proyecto Mozilla adoptó la UCI para la internacionalización en Firefox a mediados de 2012; puede seguir la discusión de ingeniería, incluidos los problemas de los sistemas de compilación y el tamaño del archivo de datos, aquí:
fuente
Parece que las soluciones anteriores no están utilizando el método de comparación e implementando el total nuevamente, así que aquí está mi solución y espero que funcione para usted (está funcionando bien).
fuente
Si no desea usar la biblioteca Boost , aquí hay una solución para usar solo el encabezado io estándar de C ++.
fuente
Si tiene que comparar una cadena fuente con más frecuencia con otras cadenas, una solución elegante es usar regex.
fuente
error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Una manera simple de comparar dos cadenas en c ++ (probado para Windows) es usando _stricmp
Si está buscando usar con std :: string, un ejemplo:
Para obtener más información aquí: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx
fuente
Esto probablemente podría hacerse mucho más eficiente, pero aquí hay una versión voluminosa con todos sus bits al descubierto.
no es tan portátil, pero funciona bien con lo que sea que esté en mi computadora (ni idea, soy de imágenes, no de palabras)
fuente
Una manera fácil de comparar cadenas que solo son diferentes en minúsculas y mayúsculas es hacer una comparación ascii. Todas las letras mayúsculas y minúsculas difieren en 32 bits en la tabla ASCII, utilizando esta información tenemos lo siguiente ...
fuente