una strlwr son saber minusculas minuscula mayusculas mayuscula letra iguales convertir contar comparar como caracteres cadenas cadena c++ string

strlwr - Comparación de cadenas insensibles a mayúsculas en C++



convertir una letra en mayuscula c++ (30)

¿Está hablando de una comparación insensible a los estúpidos o de una comparación Unicode completamente normalizada?

Una comparación tonta no encontrará cadenas que puedan ser iguales pero que no sean binarias iguales.

Ejemplo:

bool iequals(const string& a, const string& b) { return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); }); }

Son todos equivalentes pero también tienen diferentes representaciones binarias.

Dicho esto, la unicode.org/reports/tr15 debería ser una lectura obligatoria, especialmente si planea apoyar Hangul, Thaï 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

¿Cuál es la mejor manera de hacer una comparación de cadenas que no distingue entre mayúsculas y minúsculas en C ++ sin transformar una cadena a mayúsculas o minúsculas?

Indique si los métodos son compatibles con Unicode y qué tan portátiles son.


A principios de 2013, el proyecto ICU, mantenido por IBM, es una buena respuesta para esto.

site.icu-project.org

ICU es una "biblioteca Unicode portátil y completa 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 usted desea.

El Proyecto Mozilla adoptó la ICU para la internacionalización en Firefox a mediados de 2012; Puede realizar un seguimiento de la discusión de ingeniería, incluidos los problemas de sistemas de compilación y el tamaño del archivo de datos, aquí


Aprovecha las char_traits estándar. Recuerde que un std::string es de hecho un typedef para std::basic_string<char> , o más explícitamente, std::basic_string<char, std::char_traits<char> > . El tipo char_traits 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 a través de basic_string y proporcionarla con sus propios char_traits personalizados que comparen mayúsculas y minúsculas con insensibilidad.

struct ci_char_traits : public char_traits<char> { static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); } static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); } static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); } static int compare(const char* s1, const char* s2, size_t n) { while( n-- != 0 ) { if( toupper(*s1) < toupper(*s2) ) return -1; if( toupper(*s1) > toupper(*s2) ) return 1; ++s1; ++s2; } return 0; } static const char* find(const char* s, int n, char a) { while( n-- > 0 && toupper(*s) != toupper(a) ) { ++s; } return s; } }; typedef std::basic_string<char, ci_char_traits> ci_string;

Los detalles están en el gurú de la semana número 29 .


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 }


Corto y agradable. No hay otras dependencias, que extendida std C lib.

strcasecmp(str1.c_str(), str2.c_str()) == 0

devuelve true si str1 y str2 son iguales. strcasecmp posible que no exista strcasecmp , podría haber análogos stricmp , strcmpi , etc.

Código de ejemplo:

#include <iostream> #include <string> #include <string.h> //For strcasecmp(). Also could be found in <mem.h> using namespace std; /// Simple wrapper inline bool str_ignoreCase_cmp(std::string const& s1, std::string const& s2) { if(s1.length() != s2.length()) return false; // optimization since std::string holds length in variable. return strcasecmp(s1.c_str(), s2.c_str()) == 0; } /// Function object - comparator struct StringCaseInsensetiveCompare { bool operator()(std::string const& s1, std::string const& s2) { if(s1.length() != s2.length()) return false; // optimization since std::string holds length in variable. return strcasecmp(s1.c_str(), s2.c_str()) == 0; } bool operator()(const char *s1, const char * s2){ return strcasecmp(s1,s2)==0; } }; /// Convert bool to string inline char const* 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; return 0; }

Salida:

true true true true true


El problema con el impulso es que hay que vincularse y depender del impulso. No es fácil en algunos casos (por ejemplo, Android).

Y el uso de char_traits significa que todas sus comparaciones no distinguen entre mayúsculas y minúsculas, lo que no suele ser lo que usted quiere.

Esto debería ser suficiente. Debe ser razonablemente eficiente. Aunque no maneja unicode ni nada.

U212B (ANGSTROM SIGN) U0041 (LATIN CAPITAL LETTER A) + U030A (COMBINING RING ABOVE) U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).

Actualización: Versión Bonus C ++ 14 ( #include <algorithm> ):

bool iequals(const string& a, const string& b) { unsigned int sz = a.size(); if (b.size() != sz) return false; for (unsigned int i = 0; i < sz; ++i) if (tolower(a[i]) != tolower(b[i])) return false; return true; }


Escribí una versión de char_traits que no distingue entre mayúsculas y minúsculas para usar con std :: basic_string con el fin de generar una cadena std :: que no distinga entre mayúsculas y minúsculas al realizar comparaciones, búsquedas, etc. utilizando las funciones integradas de miembro std :: basic_string.

Así que 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> { static bool eq( const C& c1, const C& c2 ) { return ::toupper(c1) == ::toupper(c2); } static bool lt( const C& c1, const C& c2 ) { return ::toupper(c1) < ::toupper(c2); } static int compare( const C* s1, const C* s2, size_t N ) { return _strnicmp(s1, s2, N); } static const char* 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 ; } return 0 ; } static bool 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> { static bool eq( const wchar_t& c1, const wchar_t& c2 ) { return ::towupper(c1) == ::towupper(c2); } static bool lt( const wchar_t& c1, const wchar_t& c2 ) { return ::towupper(c1) < ::towupper(c2); } static int compare( const wchar_t* s1, const wchar_t* s2, size_t N ) { return _wcsnicmp(s1, s2, N); } static const wchar_t* find( const wchar_t* s, size_t N, const wchar_t& a ) { for( size_t i=0 ; i<N ; ++i ) { if( ::towupper(s[i]) == ::towupper(a) ) return s+i ; } return 0 ; } static bool 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;


Estoy tratando de improvisar una buena respuesta de todas las publicaciones, así que ayúdame a editar esto:

Aquí hay un método para hacer esto, aunque transforma las cadenas y no es compatible con Unicode, debería ser portátil, lo que es una ventaja:

bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) { std::string str1Cpy( str1 ); std::string str2Cpy( str2 ); std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower ); std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower ); return ( str1Cpy == str2Cpy ); }

Por lo que he leído, esto es más portátil que stricmp () porque stricmp () no es en realidad parte de la biblioteca std, sino que la mayoría de los proveedores de compiladores lo implementan.

Para obtener una implementación realmente amigable con Unicode, parece que debes salir de la biblioteca estándar. Una buena biblioteca de terceros es IBM ICU (International Components for Unicode)

También boost :: iequals proporciona una utilidad bastante buena para hacer este tipo de comparación.


FYI, strcmp() y stricmp() son vulnerables al desbordamiento de búfer, ya que solo se procesan hasta que tocan un terminador nulo. Es más seguro usar _strncmp() y _strnicmp() .



He tenido una buena experiencia al utilizar los componentes internacionales para las bibliotecas de Unicode : son extremadamente potentes y proporcionan métodos para la conversión, el soporte de configuración regional, la representación de fecha y hora, la asignación de casos (que parece que no desea) y la collation . que incluye comparación insensible a 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 de Java.

Existen métodos para realizar comparaciones normalizadas a las que hace referencia @Coincoin, e incluso pueden dar cuenta de la configuración regional, por ejemplo (y esto es un ejemplo de clasificación, no estrictamente equitativa), tradicionalmente en español (en España), la combinación de letras "ll" se ordena entre "l" y "m", así que "lz" <"ll" <"ma".


La biblioteca Boost.String tiene muchos algoritmos para hacer comparaciones insensibles a los casos, etc.

Podría implementar el suyo propio, pero ¿por qué molestarse cuando ya se ha hecho?


Mi primer pensamiento para una versión no Unicode fue hacer algo como esto:

bool caseInsensitiveStringCompare(const string& str1, const string& str2) { if (str1.size() != str2.size()) { return false; } for (string::const_iterator c1 = str1.begin(), c2 = str2.begin(); c1 != str1.end(); ++c1, ++c2) { if (tolower(*c1) != tolower(*c2)) { return false; } } return true; }


Para mis necesidades básicas de comparación de cadenas insensibles al caso, prefiero no tener que usar una biblioteca externa, ni tampoco quiero una clase de cadena separada con rasgos que no distingan mayúsculas y minúsculas que sea incompatible con todas mis otras cadenas.

Así que lo que he encontrado es esto:

bool icasecmp(const string& l, const string& r) { return l.size() == r.size() && equal(l.cbegin(), l.cend(), r.cbegin(), [](string::value_type l1, string::value_type r1) { return toupper(l1) == toupper(r1); }); } bool icasecmp(const wstring& l, const wstring& r) { return l.size() == r.size() && equal(l.cbegin(), l.cend(), r.cbegin(), [](wstring::value_type l1, wstring::value_type r1) { return towupper(l1) == towupper(r1); }); }

Una función simple con una sobrecarga para char y otra para whar_t. No utiliza nada que no sea 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 de 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, que es lo que se espera.


Parece que las soluciones anteriores no están usando el método de comparación y la implementación total nuevamente, así que aquí está mi solución y espero que funcione para usted (está funcionando bien).

#include<iostream> #include<cstring> #include<cmath> using namespace std; string tolow(string a) { for(unsigned int i=0;i<a.length();i++) { a[i]=tolower(a[i]); } return a; } int main() { string str1,str2; cin>>str1>>str2; int temp=tolow(str1).compare(tolow(str2)); if(temp>0) cout<<1; else if(temp==0) cout<<0; else cout<<-1; }


Puede usar strcasecmp en Unix o stricmp 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 para usted en la clase de cadena. Esto podría evitar hacer la comparación de cadenas costosa si las dos cadenas que está comparando no tienen la misma longitud en primer lugar.


Se puede hacer esto sin usar Boost obteniendo el puntero de cadena C con c_str() y usando strcasecmp :

std::string str1 ="aBcD"; std::string str2 = "AbCd";; if (strcasecmp(str1.c_str(), str2.c_str()) == 0) { //case insensitive equal }


Si está en un sistema POSIX, puede usar strcasecmp . Sin embargo, esta función no es parte del estándar C, ni está disponible en Windows. Esto realizará una comparación entre mayúsculas y minúsculas en los caracteres de 8 bits, siempre que la configuración regional 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.

En su defecto, un gran número de implementaciones históricas de la biblioteca C tienen las funciones stricmp () y strnicmp (). Visual C ++ en Windows cambió el nombre de todos ellos con un guión bajo, ya que 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 de caracteres anchos o multibyte equivalentes (normalmente denominados, por ejemplo, wcsicmp, mbcsicmp, etc.).

C y C ++ son en gran medida ignorantes de los problemas de internacionalización, por lo que no hay una buena solución para este problema, excepto para usar una biblioteca de terceros. Consulte IBM ICU (International Components for Unicode) si necesita una biblioteca robusta para C / C ++. ICU es para sistemas Windows y Unix.


Si tiene que comparar una cadena de origen más a menudo con otras cadenas, una solución elegante es usar expresiones regulares.

std::wstring first = L"Test"; std::wstring second = L"TEST"; std::wregex pattern(first, std::wregex::icase); bool isEqual = std::regex_match(second, pattern);


Si tienes un vector de cadenas, por ejemplo:

std::sort(std::begin(myvector), std::end(myvector), [](std::string const &a, std::string const &b) { return std::lexicographical_compare(std::begin(a), std::end(a), std::begin(b), std::end(b), [](std::string::value_type a, std::string::value_type b) { return std::tolower(a) < std::tolower(b); //case-insensitive }); });

http://ideone.com/N6sq6X


Simplemente use strcmp() para las mayúsculas y minúsculas y strcmpi() o stricmp() para una comparación que no stricmp() mayúsculas y minúsculas. Que están ambos en el archivo de cabecera <string.h>

formato:

int strcmp(const char*,const char*); //for case sensitive int strcmpi(const char*,const char*); //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 bola


Solo una nota sobre el método que finalmente elija, si ese método incluye el uso de strcmp que 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 que strcmp solo hace comparaciones byte a byte y los puntos de código Unicode codificados en utf-8 pueden tomar más de 1 byte. El único caso específico de strcmp caso de Unicode es cuando una cadena codificada con una codificación basada en bytes solo contiene puntos de código debajo de U + 00FF; por lo tanto, la comparación de bytes por bytes es suficiente.


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 punto, tenemos que 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 codificar esquemas, 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.


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()));

te da un functor que usa la configuración regional activa para convertir caracteres a minúsculas, que luego puedes usar a través de std::transform para generar cadenas en minúsculas:

std::string left = "fOo"; transform(left.begin(), left.end(), left.begin(), tolower);

Esto también funciona para wchar_t basadas en wchar_t .


Una forma sencilla de comparar dos cadenas en c ++ (probado para Windows) es usar _stricmp

// Case insensitive (could use equivalent _stricmp) result = _stricmp( string1, string2 );

Si desea utilizar con std :: string, un ejemplo:

std::string s1 = string("Hello"); if ( _stricmp(s1.c_str(), "HELLO") == 0) std::cout << "The string are equals.";

Para obtener más información aquí: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx


Ver std::lexicographical_compare :

// lexicographical_compare example #include <iostream> // std::cout, std::boolalpha #include <algorithm> // std::lexicographical_compare #include <cctype> // std::tolower // a case-insensitive comparison function: bool mycomp (char c1, char c2) { return std::tolower(c1)<std::tolower(c2); } int main () { char foo[] = "Apple"; char bar[] = "apartment"; std::cout << std::boolalpha; std::cout << "Comparing foo and bar lexicographically (foo < bar):/n"; std::cout << "Using default comparison (operator<): "; std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9); std::cout << ''/n''; std::cout << "Using mycomp as comparison object: "; std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9, mycomp); std::cout << ''/n''; return 0; }

Demo


boost :: iequals no es compatible con utf-8 en el caso de una cadena. Puedes usar boost::locale .

comparator<char,collator_base::secondary> cmpr; cout << (cmpr(str1, str2) ? "str1 < str2" : "str1 >= str2") << endl;

  • Primario: ignore los acentos y los caracteres, comparando solo las letras base. Por ejemplo, "fachada" y "fachada" son iguales.
  • Secundaria: ignora el caso del personaje, pero considera 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.

Si no desea utilizar la biblioteca de Boost , aquí está la solución utilizando solo el encabezado io estándar de C ++.

#include <iostream> struct iequal { bool operator()(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; } return 0; }


bool insensitive_c_compare(char A, char B){ static char mid_c = (''Z'' + ''a'') / 2 + ''Z''; static char up2lo = ''A'' - ''a''; /// the offset between upper and lowers if (''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 esté en mi computadora (no tengo idea, soy de imágenes y no de palabras)


std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b){return std::tolower(a)==std::tolower(b);})

Puede usar el código anterior en C ++ 14 si no está en condiciones de usar boost. Tienes que usar std::towlower para caracteres anchos.