en résumé
Utilisez le Bibliothèque de l'USI . Si vous ne le faites pas, votre routine de conversion se brisera silencieusement sur des cas dont vous n'avez probablement même pas conscience de l'existence.
Vous devez d'abord répondre à une question : Quel est le codage de votre std::string
? Est-ce que c'est ISO-8859-1 ? Ou peut-être ISO-8859-8 ? Ou encore Windows Codepage 1252 ? Est-ce que ce que vous utilisez pour convertir les majuscules en minuscules le sait ? (Ou est-ce qu'il échoue lamentablement pour les personnages sur 0x7f
?)
Si vous utilisez UTF-8 ( le seul choix sensé parmi les encodages 8 bits ) avec std::string
en tant que conteneur, vous vous trompez déjà si vous croyez que vous contrôlez encore les choses. Vous stockez une séquence de caractères multi-octets dans un conteneur qui ne connaît pas le concept de multi-octets, pas plus que la plupart des opérations que vous pouvez effectuer sur lui ! Même quelque chose d'aussi simple que .substr()
peut donner lieu à des (sous-)chaînes de caractères non valides parce que vous avez coupé au milieu d'une séquence de plusieurs octets.
Dès que vous essayez quelque chose comme std::toupper( 'ß' )
ou std::tolower( 'Σ' )
en tout l'encodage, vous avez des problèmes. Parce que 1), la norme n'opère jamais que sur un seul caractère à la fois, donc elle ne peut simplement pas tourner ß
en SS
ce qui serait correct. Et 2), la norme n'opère jamais que sur un seul caractère à la fois, elle ne peut donc pas décider si Σ
est au milieu d'un mot (où σ
serait correct), ou à la fin ( ς
). Un autre exemple serait std::tolower( 'I' )
ce qui devrait donner des résultats différents en fonction de la langue -- pratiquement partout où l'on peut s'attendre i
mais en Turquie ı
(LATIN SMALL LETTER DOTLESS I) est la bonne réponse (qui, encore une fois, représente plus d'un octet dans l'encodage UTF-8).
Donc, tout conversion de cas qui fonctionne sur un caractère à la fois, ou pire, une octet à la fois, est cassé par conception. Cela comprend tous les std::
variantes existant à l'heure actuelle.
Ensuite, il y a le point que la bibliothèque standard, pour ce qu'elle est es de faire, c'est de dépendre de quelles locales sont supporté par sur la machine sur laquelle votre logiciel est exécuté... et que faites-vous si votre locale cible fait partie de celles qui ne sont pas prises en charge par la machine de votre client ?
Donc ce que vous êtes vraiment est une classe de chaînes de caractères capable de gérer tout cela correctement, et c'est no l'un des std::basic_string<>
variantes .
(Note C++11 : std::u16string
y std::u32string
sont meilleur mais ce n'est pas encore parfait. C++20 a apporté std::u8string
mais tout ce qu'ils font, c'est de spécifier le codage . À bien d'autres égards, ils ignorent encore les mécanismes d'Unicode, comme la normalisation, la collation, ...).
Alors que Boost regarde Bien, au niveau de l'API, Boost.Locale est essentiellement une enveloppe autour de UNITÉ DE SOINS INTENSIFS . 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 être une vraie douleur parfois. (Il n'y a pas de binaires pré-compilés pour Windows qui incluent ICU, vous devez donc les fournir avec votre application, et que ouvre une toute nouvelle boîte de vers...)
Personnellement, je recommanderais d'obtenir la prise en charge complète d'Unicode directement de la bouche du cheval et d'utiliser la fonction UNITÉ DE SOINS INTENSIFS directement à la bibliothèque :
#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. Non <algorithm>
-Une solution basée sur les technologies de l'information et de la communication peut vous offrir cela.