tl; dr
Use la biblioteca de la UCI . Si no lo hace, su rutina de conversión se interrumpirá silenciosamente en casos de los que probablemente ni siquiera esté al tanto.
Primero tienes que responder una pregunta: ¿Cuál es la codificación de tu std::string
? ¿Es ISO-8859-1? O tal vez ISO-8859-8? ¿O la página de códigos de Windows 1252? ¿Lo que sea que esté usando para convertir mayúsculas a minúsculas lo sabe? (¿O falla miserablemente para los personajes 0x7f
?)
Si está utilizando UTF-8 (la única opción sensata entre las codificaciones de 8 bits) std::string
como contenedor, ya se está engañando a sí mismo al creer que todavía tiene el control de las cosas, porque está almacenando una secuencia de caracteres multibyte en un contenedor que no conoce el concepto multibyte. Incluso algo tan simple como .substr()
una bomba de relojería. (Debido a que dividir una secuencia multibyte dará como resultado una (sub) cadena no válida).
Y tan pronto como intente algo como std::toupper( 'ß' )
, en cualquier codificación, estará en serios problemas. (Debido a que simplemente no es posible hacer esto "correctamente" con la biblioteca estándar, que solo puede entregar un carácter de resultado, no el "SS"
necesario aquí.) [1] Otro ejemplo sería std::tolower( 'I' )
, que debería producir resultados diferentes dependiendo de la configuración regional . En Alemania, 'i'
sería correcto; en Turquía, 'ı'
(LETRA PEQUEÑA LATINA DOTLESS I) es el resultado esperado (que, nuevamente, es más de un byte en la codificación UTF-8). Otro ejemplo es el Sigma griego , mayúsculas '∑'
, minúsculas 'σ'
... excepto al final de una palabra, donde está 'ς'
.
Entonces, cualquier conversión de caso que funcione en un personaje a la vez, o peor, un byte a la vez, se rompe por diseño.
Luego está el punto de que la biblioteca estándar, por lo que es capaz de hacer, depende de qué configuraciones regionales sean compatibles con la máquina en la que se está ejecutando su software ... ¿y qué hace si no lo es?
Entonces, lo que realmente está buscando es una clase de cadena que sea capaz de lidiar con todo esto correctamente, y esa no es ninguna de las std::basic_string<>
variantes .
(Nota de C ++ 11: std::u16string
y std::u32string
son mejores , pero aún no son perfectos. C ++ 20 traído std::u8string
, pero todo lo que hacen es especificar la codificación. En muchos otros aspectos, siguen ignorando la mecánica Unicode, como la normalización, la clasificación, ... .)
Mientras que Boost se ve bien, API sabia, Boost.Locale es básicamente un contenedor alrededor de la UCI . Si Boost se compila con soporte de ICU ... si no es así, Boost.Locale se limita al soporte de entorno local compilado para la biblioteca estándar.
Y créanme, hacer que Boost compile con UCI puede ser un verdadero dolor a veces. (No hay binarios precompilados para Windows, por lo que tendría que proporcionarlos junto con su aplicación, y eso abre una nueva lata de gusanos ...)
Entonces, personalmente, recomendaría obtener soporte completo de Unicode directamente de la boca del caballo y usar la biblioteca de la UCI directamente:
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>
#include <iostream>
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;
}
Compilar (con G ++ en este ejemplo):
g++ -Wall example.cpp -licuuc -licuio
Esto da:
ὀδυσσεύς
Tenga en cuenta que la conversión Σ <-> σ en el medio de la palabra, y la conversión Σ <-> ς al final de la palabra. Ninguna <algorithm>
solución basada en eso puede darte eso.
[1] En 2017, el Consejo de Ortografía Alemana dictaminó que "ẞ" U + 1E9E LATIN CAPITAL LETTER SHARP S podría usarse oficialmente, como una opción junto a la conversión tradicional "SS" para evitar la ambigüedad, por ejemplo, en pasaportes (donde los nombres están en mayúscula) ) Mi hermoso ejemplo, que quedó obsoleto por decisión del comité ...