tl; dr
Utilizzare la libreria ICU . In caso contrario, la routine di conversione si interromperà silenziosamente in casi che probabilmente non si conoscono.
Per prima cosa devi rispondere a una domanda: qual è la tua codificastd::string
? È ISO-8859-1? O forse ISO-8859-8? O Windows Codepage 1252? Qualunque cosa tu stia usando per convertire maiuscole in minuscole lo sa? (O fallisce miseramente per i personaggi finiti 0x7f
?)
Se stai usando UTF-8 (l'unica scelta sana tra le codifiche a 8 bit) con std::string
come contenitore, stai già ingannando te stesso nel credere di avere ancora il controllo delle cose, perché stai memorizzando una sequenza di caratteri multibyte in un contenitore che non è a conoscenza del concetto multibyte. Anche qualcosa di semplice come .substr()
una bomba a orologeria. (Perché la divisione di una sequenza multibyte comporterà una stringa (sotto) non valida.)
E non appena provi qualcosa del genere std::toupper( 'ß' )
, in qualsiasi codifica, sei in guai seri. (Perché semplicemente non è possibile fare questo "giusto" con la libreria standard, che può fornire solo un carattere risultato, non il "SS"
necessario qui.) [1] Un altro esempio potrebbe essere std::tolower( 'I' )
, che dovrebbe produrre risultati diversi a seconda delle impostazioni locali . In Germania, 'i'
sarebbe corretto; in Turchia, 'ı'
(LATIN SMALL LOTTER DOTLESS I) è il risultato atteso (che, di nuovo, è più di un byte nella codifica UTF-8). Ancora un altro esempio è il greco Sigma , maiuscolo '∑'
, minuscolo 'σ'
... tranne alla fine di una parola, dove si trova 'ς'
.
Pertanto, qualsiasi conversione di caso che funziona su un personaggio alla volta, o peggio, su un byte alla volta, viene interrotta in base alla progettazione.
Quindi c'è il punto che la libreria standard, per quello che è in grado di fare, dipende da quali impostazioni locali sono supportate sulla macchina su cui è in esecuzione il software ... e cosa fai se non lo è?
Quindi quello che stai veramente cercando è una classe di stringhe in grado di gestire correttamente tutto ciò e che non sia una delle std::basic_string<>
varianti .
(Nota C ++ 11: std::u16string
e std::u32string
sono migliori , ma ancora non perfetti. C ++ 20 ha portato std::u8string
, ma tutto ciò che fa è specificare la codifica. Per molti altri aspetti rimangono ancora ignoranti della meccanica Unicode, come la normalizzazione, le regole di confronto, .. .)
Mentre Boost sembra bello, per quanto riguarda le API, Boost.Locale è fondamentalmente un wrapper per ICU . Se Boost è compilato con il supporto ICU ... in caso contrario, Boost.Locale è limitato al supporto locale compilato per la libreria standard.
E mi creda, ottenendo Boost di compilare con terapia intensiva può essere un vero e proprio dolore a volte. (Non ci sono file binari precompilati per Windows, quindi dovresti fornirli insieme alla tua applicazione e questo aprirà una nuova lattina di worm ...)
Quindi personalmente consiglierei di ottenere il pieno supporto Unicode direttamente dalla bocca del cavallo e di usare direttamente la libreria ICU :
#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;
}
Compila (con G ++ in questo esempio):
g++ -Wall example.cpp -licuuc -licuio
Questo da:
ὀδυσσεύς
Nota che la conversione Σ <-> σ nel mezzo della parola e la conversione Σ <-> ς alla fine della parola. Nessuna <algorithm>
soluzione di base può darti questo.
[1] Nel 2017, il Consiglio per l'ortografia tedesca ha stabilito che "ẞ" U + 1E9E LATTER CAPITAL LARTER SHARP S potrebbe essere utilizzato ufficialmente, come opzione accanto alla tradizionale conversione "SS" per evitare ambiguità, ad esempio nei passaporti (in cui i nomi sono scritti in maiuscolo ). Il mio bellissimo esempio, reso obsoleto dalla decisione della commissione ...