tl; dr
Utilisez la bibliothèque ICU . Si vous ne le faites pas, votre routine de conversion se brisera silencieusement sur des cas dont vous n'êtes probablement pas au courant.
Vous devez d'abord répondre à une question: quel est l' encodage de votre std::string
? Est-ce ISO-8859-1? Ou peut-être ISO-8859-8? Ou Windows Codepage 1252? Est-ce que tout ce que vous utilisez pour convertir des majuscules en minuscules le sait? (Ou échoue-t-il misérablement pour les personnages 0x7f
?)
Si vous utilisez UTF-8 (le seul choix sensé parmi les encodages 8 bits) avec std::string
comme conteneur, vous vous trompez déjà en pensant que vous contrôlez toujours les choses, car vous stockez une séquence de caractères multi-octets dans un conteneur qui n'est pas au courant du concept multi-octets. Même quelque chose d'aussi simple qu'une .substr()
bombe à retardement. (Parce que le fractionnement d'une séquence multi-octets entraînera une (sous-) chaîne invalide.)
Et dès que vous essayez quelque chose comme std::toupper( 'ß' )
, dans n'importe quel encodage, vous êtes en grande difficulté. (Parce qu'il n'est tout simplement pas possible de faire cela "correctement" avec la bibliothèque standard, qui ne peut fournir qu'un seul caractère de résultat, pas le caractère "SS"
nécessaire ici.) [1] Un autre exemple serait std::tolower( 'I' )
, qui devrait donner des résultats différents selon les paramètres régionaux . En Allemagne, ce 'i'
serait correct; en Turquie, 'ı'
(LATINE LETTRE MINUSCULE DOTLESS I) est le résultat attendu (qui, encore une fois, est de plus d'un octet dans le codage UTF-8). Encore un autre exemple est le Sigma grec , en majuscule '∑'
, en minuscule 'σ'
... sauf à la fin d'un mot, où il est 'ς'
.
Ainsi, toute conversion de cas qui fonctionne sur un caractère à la fois, ou pire, un octet à la fois, est cassée par conception.
Ensuite, il y a le point que la bibliothèque standard, pour ce qu'elle est capable de faire, dépend des paramètres régionaux pris en charge sur la machine sur laquelle votre logiciel s'exécute ... et que faites-vous si ce n'est pas le cas?
Donc, ce que vous cherchez vraiment, c'est une classe de chaînes capable de gérer tout cela correctement, et ce n'est pas une des std::basic_string<>
variantes .
(Remarque C ++ 11: std::u16string
et std::u32string
sont meilleurs , mais toujours pas parfaits. C ++ 20 apporté std::u8string
, mais tout cela ne fait que spécifier l'encodage. À bien d'autres égards, ils ignorent encore la mécanique Unicode, comme la normalisation, le classement, .. .)
Alors que Boost a l' air sympa, API sage, Boost.Locale est essentiellement un wrapper autour de l' ICU . Si Boost est compilé avec le support ICU ... si ce n'est pas le cas, Boost.Locale est limité au support local compilé pour la bibliothèque standard.
Et croyez-moi, obtenir Boost pour compiler avec ICU peut parfois être une vraie douleur. (Il n'y a pas de binaires précompilés pour Windows, vous devez donc les fournir avec votre application, ce qui ouvre une toute nouvelle boîte de vers ...)
Donc, personnellement, je recommanderais d'obtenir un support Unicode complet directement de la bouche du cheval et d'utiliser directement la bibliothèque 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;
}
Compilez (avec G ++ dans cet exemple):
g++ -Wall example.cpp -licuuc -licuio
Cela donne:
ὀδυσσεύς
Notez que la conversion Σ <-> σ au milieu du mot et la conversion Σ <-> ς à la fin du mot. Aucune <algorithm>
solution basée sur le système ne peut vous apporter cela.
[1] En 2017, le Conseil de l'orthographe allemande a jugé que "ẞ" U + 1E9E LETTRE MAJUSCULE LATINE SHARP S pouvait être utilisé officiellement, en option à côté de la conversion traditionnelle "SS" pour éviter toute ambiguïté, par exemple dans les passeports (où les noms sont en majuscules) ). Mon bel exemple, rendu obsolète par décision du comité ...