Si te encuentras con algo que te causa duda puedes dejarlo en los comentarios y te responderemos lo mas rápido que podamos.
Solución:
Adaptado de Preguntas no tan frecuentes:
#include
#include
#include
std::string data = "Abc";
std::transform(data.begin(), data.end(), data.begin(),
[](unsigned char c) return std::tolower(c); );
Realmente no te saldrás con la tuya sin iterar a través de cada personaje. De lo contrario, no hay forma de saber si el carácter está en minúsculas o en mayúsculas.
Si realmente odias tolower()
, aquí hay una alternativa especializada solo en ASCII que no te recomiendo que uses:
char asciitolower(char in)
if (in <= 'Z' && in >= 'A')
return in - ('Z' - 'z');
return in;
std::transform(data.begin(), data.end(), data.begin(), asciitolower);
Sé consciente de tolower()
solo puede hacer una sustitución por carácter de un solo byte, lo que no es adecuado para muchos scripts, especialmente si se usa una codificación de varios bytes como UTF-8.
Boost proporciona un string algoritmo para esto:
#include
std::string str = "HELLO, WORLD!";
boost::algorithm::to_lower(str); // modifies str
O, para no en el lugar:
#include
const std::string str = "HELLO, WORLD!";
const std::string lower_str = boost::algorithm::to_lower_copy(str);
tl; dr
Utilice la biblioteca de la UCI. Si no lo hace, su rutina de conversión se interrumpirá silenciosamente en casos que probablemente ni siquiera sepa que existen.
Primero tienes que responder una pregunta: ¿Cuál es el codificacion de tu std::string
? ¿Es ISO-8859-1? ¿O quizás ISO-8859-8? ¿O la página de códigos de Windows 1252? ¿Lo sabe todo lo que esté usando para convertir mayúsculas a minúsculas? (¿O falla miserablemente para los personajes sobre 0x7f
?)
Si está utilizando UTF-8 (la única opción sensata entre las codificaciones de 8 bits) con std::string
como contenedor, ya se está engañando a sí mismo si cree que todavía tiene el control de las cosas. Está almacenando una secuencia de caracteres multibyte en un contenedor que no conoce el concepto multibyte, ¡y tampoco la mayoría de las operaciones que puede realizar en él! Incluso algo tan simple como .substr()
podría dar como resultado cadenas (sub) no válidas porque se divide en medio de una secuencia multibyte.
Tan pronto como intente algo como std::toupper( 'ß' )
, o std::tolower( 'Σ' )
en alguna codificación, estás en problemas. Porque 1), el estándar solo opera en un carácter a la vez, por lo que simplemente no puede girar ß
dentro SS
como sería correcto. Y 2), el estándar solo opera en un carácter a la vez, por lo que no puede decidir si Σ
está en medio de una palabra (donde σ
sería correcto), o al final (ς
). Otro ejemplo sería std::tolower( 'I' )
, que debería producir resultados diferentes dependiendo de la localidad – prácticamente en todos los lugares que esperarías i
, pero en Turquía ı
(LETRA MINÚSCULA LATINA SIN PUNTOS I) es la respuesta correcta (que, nuevamente, es más de un byte en codificación UTF-8).
Entonces, alguna conversión de casos que funciona en un personaje a la vez, o peor, un byte a la vez, se rompe por diseño. Esto incluye todos los std::
variantes existentes en este momento.
Luego está el punto de que la biblioteca estándar, por lo que es capaz de hacer, depende de las configuraciones regionales soportado en la máquina en la que se está ejecutando su software … ¿y qué debe hacer si su configuración regional de destino se encuentra entre las no admitidas en la máquina de su cliente?
Entonces que eres De Verdad buscando es un string clase que es capaz de lidiar con todo esto correctamente, y eso es no cualquiera de los std::basic_string<>
variantes.
(Nota de C ++ 11: std::u16string
y std::u32string
están mejor, pero aún no perfecto. C ++ 20 traído std::u8string
, pero todo lo que hacen es especificar el codificacion. En muchos otros aspectos, todavía ignoran la mecánica Unicode, como la normalización, la intercalación, …)
Mientras Boost aspecto agradable, en cuanto a API, Boost.Locale es básicamente una envoltura de ICU. Si Boost es compilado con soporte de ICU … si no lo es, Boost.Locale se limita al soporte de configuración regional compilado para la biblioteca estándar.
Y créeme obtener El impulso para compilar con UCI puede ser un verdadero dolor a veces. (No hay binarios precompilados para Windows que incluyan ICU, por lo que tendría que proporcionarlos junto con su aplicación y ese abre una nueva lata de gusanos …)
Así que personalmente recomendaría obtener soporte Unicode completo directamente de la boca del caballo y usar la biblioteca ICU directamente:
#include
#include
#include
#include
int main()
/* "Odysseus" */
char const * someString = u8"ΟΔΥΣΣΕΥΣ";
icu::UnicodeString someUString( someString, "UTF-8" );
// Setting the locale explicitly here for completeness.
// Usually you would use the user-specified system locale,
// which *does* make a difference (see ı vs. i above).
std::cout << someUString.toLower( "el_GR" ) << "n";
std::cout << someUString.toUpper( "el_GR" ) << "n";
return 0;
Compile (con G ++ en este ejemplo):
g++ -Wall example.cpp -licuuc -licuio
Esto da:
ὀδυσσεύς
Tenga en cuenta que el Σ<->σ conversión en el medio de la palabra, y Σ<->ς conversión al final de la palabra. No
-basada en una solución puede darte eso.
Recuerda dar recomendación a este enunciado si te fue de ayuda.