Convertir entre la chaîne, la chaîne u16ssortingng et la chaîne u32

J’ai cherché un moyen de convertir entre les types de chaîne Unicode et est tombé sur cette méthode . Non seulement je ne comprends pas complètement la méthode (il n’y a pas de commentaires), mais l’article implique également qu’à l’avenir, il y aura de meilleures méthodes.

Si c’est la meilleure méthode, pourriez-vous s’il vous plaît indiquer ce qui fait que cela fonctionne, et sinon je voudrais entendre des suggestions pour de meilleures méthodes.

mbstowcs() et wcstombs() ne sont pas nécessairement convertis en UTF-16 ou UTF-32, ils sont convertis en wchar_t et quel que soit le codage local wchar_t . Tous les parameters régionaux Windows utilisent un wchar_t et UTF-16 de deux octets, mais les autres plates-formes principales utilisent un wchar_t 4 octets avec UTF-32 (ou même un codage non-Unicode pour certains parameters régionaux). Une plate-forme qui ne supporte que les encodages à un octet pourrait même avoir un octet wchar_t et le codage diffère selon les parameters régionaux. Donc, wchar_t me semble être un mauvais choix pour la portabilité et Unicode. *

Quelques meilleures options ont été introduites dans C ++ 11; nouvelles spécialisations de std :: codecvt, de nouvelles classes de codecvt, et un nouveau modèle pour les utiliser pour des conversions très pratiques.

Tout d’abord, la nouvelle classe de modèle pour l’utilisation du codecvt est std :: wssortingng_convert. Une fois que vous avez créé une instance d’une classe std :: wssortingng_convert, vous pouvez facilement convertir entre les chaînes:

 std::wssortingng_convert<...> convert; // ... filled in with a codecvt to do UTF-8 <-> UTF-16 std::ssortingng utf8_ssortingng = u8"This ssortingng has UTF-8 content"; std::u16ssortingng utf16_ssortingng = convert.from_bytes(utf8_ssortingng); std::ssortingng another_utf8_ssortingng = convert.to_bytes(utf16_ssortingng); 

Pour effectuer des conversions différentes, il vous suffit de définir différents parameters, dont l’un est une facette codecvt. Voici quelques nouvelles facettes faciles à utiliser avec wssortingng_convert:

 std::codecvt_utf8_utf16 // converts between UTF-8 <-> UTF-16 std::codecvt_utf8 // converts between UTF-8 <-> UTF-32 std::codecvt_utf8 // converts between UTF-8 <-> UCS-2 (warning, not UTF-16! Don't bother using this one) 

Exemples d’utilisation de ceux-ci:

 std::wssortingng_convert,char16_t> convert; std::ssortingng a = convert.to_bytes(u"This ssortingng has UTF-16 content"); std::u16ssortingng b = convert.from_bytes(u8"blah blah blah"); 

Les nouvelles spécialisations std :: codecvt sont un peu plus difficiles à utiliser car elles ont un destructeur protégé. Pour contourner ce problème, vous pouvez définir une sous-classe avec un destructeur ou utiliser la fonction std :: use_facet pour obtenir une instance de codecvt existante. En outre, un problème lié à ces spécialisations est que vous ne pouvez pas les utiliser dans Visual Studio 2010 car la spécialisation de modèle ne fonctionne pas avec les types typedef’d et que le compilateur définit char16_t et char32_t comme des typedefs. Voici un exemple de définition de votre propre sous-classe de codecvt:

 template  struct codecvt : std::codecvt { ~codecvt(){} }; std::wssortingng_convert,char16_t> convert16; std::wssortingng_convert,char32_t> convert32; 

La spécialisation char16_t convertit entre UTF-16 et UTF-8. La spécialisation char32_t, UTF-32 et UTF-8.

Notez que ces nouvelles conversions fournies par C ++ 11 n’incluent aucun moyen de convertir directement entre UTF-32 et UTF-16. Au lieu de cela, il suffit de combiner deux instances de std :: wssortingng_convert.


***** Je pensais append une note sur wchar_t et son objective, pour souligner pourquoi il ne devrait pas être utilisé pour le code Unicode ou internationalisé. Voici une version courte de ma réponse https://stackoverflow.com/a/11107667/365496

Qu’est-ce que wchar_t?

wchar_t est défini de telle sorte que le codage de caractère de n’importe quel environnement local peut être converti en wchar_t où chaque wchar_t représente exactement un sharepoint code:

Type wchar_t est un type distinct dont les valeurs peuvent représenter des codes distincts pour tous les membres du plus grand jeu de caractères étendu spécifié parmi les parameters régionaux pris en charge (22.3.1). – [fondamental.fondamental] 3.9.1 / 5

Cela ne nécessite pas que wchar_t soit suffisamment grand pour représenter n’importe quel caractère de tous les parameters régionaux simultanément. En d’autres termes, le codage utilisé pour wchar_t peut différer selon les parameters régionaux. Ce qui signifie que vous ne pouvez pas nécessairement convertir une chaîne en wchar_t en utilisant un seul paramètre régional, puis reconvertir en char en utilisant un autre paramètre régional.

Puisque cela semble être la principale utilisation pratique de wchar_t, vous vous demandez peut-être à quoi cela sert si ce n’est pas le cas.

L’idée et le but de wchar_t étaient de simplifier le traitement du texte en le définissant de manière à ce qu’il nécessite une correspondance unitaire entre les unités de code d’une chaîne et les caractères du texte, permettant ainsi d’utiliser les mêmes algorithmes simples utilisés avec les chaînes ASCII travailler avec d’autres langues.

Malheureusement, les exigences de wchar_t supposent une correspondance univoque entre les caractères et les points de code pour y parvenir. Unicode rompt cette hypothèse, vous ne pouvez donc pas non plus utiliser wchar_t pour des algorithmes de texte simples.

Cela signifie que le logiciel portable ne peut pas utiliser wchar_t comme représentation commune du texte entre les parameters régionaux ou pour permettre l’utilisation d’algorithmes de texte simples.

A quoi sert wchar_t aujourd’hui?

Pas grand chose, pour le code portable de toute façon. Si __STDC_ISO_10646__ est défini, les valeurs de wchar_t représentent directement les points de code Unicode ayant les mêmes valeurs dans tous les parameters régionaux. Cela permet de faire sans risque les conversions inter-locales mentionnées plus haut. Cependant, vous ne pouvez pas vous fier uniquement à lui pour décider que vous pouvez utiliser wchar_t de cette manière car, même si la plupart des plates-formes unix le définissent, Windows ne le fait pas même si Windows utilise le même paramètre local wchar_t.

La raison pour laquelle Windows ne définit pas __STDC_ISO_10646__ je pense parce que Windows utilise UTF-16 comme encodage wchar_t, et parce que UTF-16 utilise des paires de substitution pour représenter des points de code supérieurs à U + FFFF, ce qui signifie que UTF-16 exigences pour __STDC_ISO_10646__ .

Pour le code spécifique à la plateforme, wchar_t peut être plus utile. Il est essentiellement nécessaire sous Windows (par exemple, certains fichiers ne peuvent pas être ouverts sans utiliser les noms de fichiers wchar_t), bien que Windows soit la seule plate-forme pour laquelle je le connais (donc peut-être que wchar_t est ‘Windows_char_t’).

À posteriori, wchar_t n’est clairement pas utile pour simplifier la gestion du texte ou comme stockage pour du texte indépendant des parameters régionaux. Le code portable ne doit pas tenter de l’utiliser à ces fins.

J’ai écrit des fonctions d’aide pour convertir vers / à partir de chaînes UTF8 (C ++ 11):

 #include  #include  #include  using namespace std; template  ssortingng toUTF8(const basic_ssortingng, allocator>& source) { ssortingng result; wssortingng_convert, T> convertor; result = convertor.to_bytes(source); return result; } template  void fromUTF8(const ssortingng& source, basic_ssortingng, allocator>& result) { wssortingng_convert, T> convertor; result = convertor.from_bytes(source); } 

Exemple d’utilisation:

 // Unicode <-> UTF8 { wssortingng uStr = L"Unicode ssortingng"; ssortingng str = toUTF8(uStr); wssortingng after; fromUTF8(str, after); assert(uStr == after); } // UTF16 <-> UTF8 { u16ssortingng uStr; uStr.push_back('A'); ssortingng str = toUTF8(uStr); u16ssortingng after; fromUTF8(str, after); assert(uStr == after); } 

Pour autant que je sache, C ++ ne fournit aucune méthode standard pour convertir depuis ou vers UTF-32. Cependant, pour UTF-16, il existe les méthodes mbstowcs (chaîne de caractères multi-octets à large) et l’inverse, wcstombs .

Si vous avez également besoin de UTF-32, vous avez besoin d’ iconv , qui est dans POSIX 2001 mais pas dans le standard C, donc sous Windows, vous aurez besoin d’un remplacement comme libiconv .

Voici un exemple d’utilisation de mbstowcs :

 #include  #include  #include  using namespace std; wssortingng widessortingng(const ssortingng &text); int main() { ssortingng text; cout << "Enter something: "; cin >> text; wcout << L"You entered " << widestring(text) << ".\n"; return 0; } wstring widestring(const string &text) { wstring result; result.resize(text.length()); mbstowcs(&result[0], &text[0], text.length()); return result; } 

L'inverse va comme ceci:

 ssortingng mbssortingng(const wssortingng &text) { ssortingng result; result.resize(text.length()); wcstombs(&result[0], &text[0], text.length()); return result; } 

Nitpick: Oui, je sais que la taille de wchar_t est définie par l'implémentation, donc 4 octets (UTF-32). Cependant, je ne connais pas de compilateur qui le fait.