tl; dr
Use a biblioteca da UTI . Caso contrário, sua rotina de conversão será interrompida silenciosamente nos casos que você provavelmente nem conhece.
Primeiro você tem que responder a uma pergunta: Qual é a codificação do seu std::string
? É ISO-8859-1? Ou talvez ISO-8859-8? Ou página de código 1252 do Windows? O que você está usando para converter maiúsculas para minúsculas sabe disso? (Ou falha miseravelmente para os personagens terminados 0x7f
?)
Se você estiver usando UTF-8 (a única opção sensata entre as codificações de 8 bits) std::string
como contêiner, já estará enganando-se a acreditar que ainda está no controle das coisas, porque está armazenando uma sequência de caracteres multibyte em um contêiner que não conhece o conceito multibyte. Mesmo algo tão simples quanto .substr()
uma bomba-relógio. (Como a divisão de uma sequência multibyte resultará em uma (sub)) string inválida.)
E assim que você tenta algo como std::toupper( 'ß' )
, em qualquer codificação, está com problemas profundos. (Como simplesmente não é possível fazer isso "corretamente" com a biblioteca padrão, que pode fornecer apenas um caractere de resultado, não o "SS"
necessário aqui.) [1] Outro exemplo seria std::tolower( 'I' )
: o que deve gerar resultados diferentes, dependendo da localidade . Na Alemanha, 'i'
estaria correto; na Turquia, 'ı'
(LETRA LATINA PEQUENA I) é o resultado esperado (que, novamente, é mais de um byte na codificação UTF-8). Ainda outro exemplo é o sigma grego , maiúsculo '∑'
e minúsculo 'σ'
... exceto no final de uma palavra, onde está 'ς'
.
Portanto, qualquer conversão de caso que funcione em um caractere de cada vez, ou pior, em um byte de cada vez, é interrompida pelo design.
Depois, há o ponto de que a biblioteca padrão, para o que é capaz de fazer, depende de quais localidades são suportadas na máquina em que seu software está executando ... e o que você faz se não estiver?
Então, o que você realmente está procurando é uma classe de string capaz de lidar com tudo isso corretamente, e essa não é nenhuma das std::basic_string<>
variantes .
(Nota do C ++ 11: std::u16string
e std::u32string
são melhores , mas ainda não são perfeitas. O C ++ 20 trouxe std::u8string
, mas tudo o que faz é especificar a codificação. Em muitos outros aspectos, eles ainda permanecem ignorantes da mecânica do Unicode, como normalização, agrupamento, etc. .)
Enquanto o Boost parece bom, em termos de API, o Boost.Locale é basicamente um invólucro em torno da ICU . Se o Boost for compilado com suporte à ICU ... se não for, o Boost.Locale será limitado ao suporte de localidade compilado para a biblioteca padrão.
E acredite em mim, fazer com que o Boost compile com a UTI pode ser uma dor real às vezes. (Como não existem binários pré-compilados para o Windows, você precisará fornecê-los juntamente com o aplicativo e isso abre uma nova lata de worms ...)
Então, pessoalmente, eu recomendaria obter suporte completo a Unicode diretamente da boca do cavalo e usar a biblioteca da ICU diretamente:
#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;
}
Compile (com G ++ neste exemplo):
g++ -Wall example.cpp -licuuc -licuio
Isto dá:
ὀδυσσεύς
Observe que a conversão Σ <-> σ no meio da palavra e a conversão Σ <-> ς no final da palavra. Uma <algorithm>
solução não baseada pode lhe dar isso.
[1] Em 2017, o Conselho de Ortografia Alemã determinou que "ẞ" U + 1E9E LETRA DE CAPITAL LATINA SHARP S poderia ser usada oficialmente, como uma opção ao lado da conversão tradicional de "SS" para evitar ambiguidade, por exemplo, em passaportes (onde os nomes são maiúsculos ) Meu lindo exemplo, tornado obsoleto por decisão do comitê ...