47 votes

Convertir entre chaîne, u16string et u32string

Je cherchais un moyen de convertir les types de chaîne Unicode et je suis tombé sur cette méthode . Non seulement je ne comprends pas complètement la méthode (il n'y a pas de commentaires), mais cet article implique qu'à l'avenir, il y aura de meilleures méthodes.

Si c’est la meilleure méthode, pourriez-vous préciser ce qui fait que cela fonctionne, sinon, j'aimerais entendre des suggestions pour de meilleures méthodes.

96voto

bames53 Points 38303

mbstowcs() et wcstombs() n'ont pas nécessairement convertir en UTF-16 ou UTF-32, ils convertir wchar_t , et quelle que soit la locale wchar_t encodage. Tous les paramètres régionaux Windows utilise deux octets wchar_t et UTF-16 comme le codage, mais les autres grandes plates-formes utilisent un 4 octets wchar_t avec de l'UTF-32 (ou même un non-codage Unicode pour certains endroits). Une plate-forme qui prend en charge uniquement un octet codages pourrait même avoir un seul octet wchar_t et ont l'encodage diffèrent par les paramètres régionaux. Donc, wchar_t me semble être un mauvais choix pour la portabilité et Unicode. *

Certains de meilleures options ont été introduits dans C++11; de nouvelles spécialisations de std::codecvt, de nouvelles codecvt classes, et un nouveau modèle pour rendre leur utilisation pour les conversions très pratique.

Première de la nouvelle classe de modèle pour l'utilisation de codecvt est std::wstring_convert. Une fois que vous avez créé une instance d'un std::wstring_convert classe, vous pouvez convertir facilement entre les chaînes:

std::wstring_convert<...> convert; // ... filled in with a codecvt to do UTF-8 <-> UTF-16
std::string utf8_string = u8"This string has UTF-8 content";
std::u16string utf16_string = convert.from_bytes(utf8_string);
std::string another_utf8_string = convert.to_bytes(utf16_string);

Pour faire différentes conversion, vous avez juste besoin de différents paramètres du modèle, dont l'un est une facette codecvt. Voici de nouvelles facettes qui sont faciles à utiliser avec wstring_convert:

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

Exemples d'utilisation de ces:

std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
std::string a = convert.to_bytes(u"This string has UTF-16 content");
std::u16string b = convert.from_bytes(u8"blah blah blah");

La nouvelle std::codecvt spécialisations sont un peu plus difficiles à utiliser car ils ont protégé destructeur. Pour obtenir autour de ce que vous pouvez définir une sous-classe qui a un destructeur, ou vous pouvez utiliser les std::use_facet fonction de modèle pour obtenir un existant codecvt instance. Aussi, un problème avec ces spécialisations est que vous ne pouvez pas les utiliser dans Visual Studio 2010 en raison de spécialisation de modèle ne fonctionne pas avec typedef avais types et que le compilateur définit char16_t et char32_t que les typedefs. Voici un exemple de la définition de votre propre sous-classe de codecvt:

template <class internT, class externT, class stateT>
struct codecvt : std::codecvt<internT,externT,stateT>
{ ~codecvt(){} };

std::wstring_convert<codecvt<char16_t,char,std::mbstate_t>,char16_t> convert16;
std::wstring_convert<codecvt<char32_t,char,std::mbstate_t>,char32_t> convert32;

Le char16_t spécialisation convertit entre le format UTF-16 et UTF-8. Le char32_t spécialisation, UTF-32 et UTF-8.

Notez que ces nouvelles conversions prévues par le C++11 ne comprennent pas de toute façon de convertir directement entre UTF-32 et UTF-16. Au lieu de cela il vous suffit de combiner les deux instances de std::wstring_convert.


* Je pensais que je voudrais ajouter une note sur wchar_t et de son objectif, à souligner pourquoi il ne doit généralement pas être utilisé pour l'Unicode ou portable internationalisés code. Ce qui suit est une version courte de ma réponse http://stackoverflow.com/a/11107667/365496

Qu'est-ce que wchar_t?

wchar_t est définie de telle façon que tous les paramètres régionaux de l'encodage peut être converti wchar_t où tous les wchar_t représente exactement une codepoint:

Type wchar_t est un type distinct dont les valeurs peuvent représenter des codes distincts pour tous les membres de la plus grande étendue de caractère spécifié parmi les paramètres régionaux pris en charge (22.3.1). -- [de base.fondamentaux] 3.9.1/5

Ce n'est pas exiger que wchar_t être suffisamment grand pour représenter tous les caractères de toutes les langues simultanément. Qui est, le codage utilisé pour les wchar_t peuvent différer entre les paramètres régionaux. Ce qui signifie que vous ne pouvez pas nécessairement convertir une chaîne de wchar_t à l'aide de l'un des paramètres régionaux et ensuite de les convertir en arrière de l'omble à l'aide d'une autre région.

Depuis qui semble être la principale utilisation dans la pratique pour wchar_t vous pourriez vous demander ce que c'est bon pour si pas que.

L'original de l'intention et le but de wchar_t était de faire du traitement de texte simple en le définissant telle qu'elle nécessite un one-to-one mapping à partir d'une chaîne de code-parts pour le texte des personnages, permettant ainsi l'utilisation de simples algorithmes utilisés avec des chaînes ascii de travailler avec d'autres langues.

Malheureusement, les exigences sur wchar_t assumer un one-to-one mapping entre les personnages et codepoints pour atteindre cet objectif. Unicode des pauses d'une hypothèse, de sorte que vous ne pouvez pas l'utiliser en toute sécurité wchar_t pour du texte simple, des algorithmes de soit.

Cela signifie que le logiciel portable ne peut pas utiliser wchar_t soit comme une représentation commune pour le texte entre les paramètres régionaux, ou à permettre l'utilisation de texte simple des algorithmes.

Quel est wchar_t aujourd'hui?

Pas beaucoup, pour un code portable, de toute façon. Si __STDC_ISO_10646__ est défini, les valeurs de wchar_t représentent directement Unicode codepoints avec les mêmes valeurs dans tous les lieux. Que fait-il sécuritaire de faire de l'inter-régionaux des conversions mentionné plus tôt. Cependant, vous ne pouvez pas compter uniquement sur elle de décider que vous pouvez utiliser wchar_t de cette façon parce que, bien que la plupart des plates-formes unix définir, Windows n'a pas même si Windows utilise le même wchar_t locale dans toutes les régions.

La raison pour Windows ne définit __STDC_ISO_10646__ je crois, à cause de Windows utiliser l'UTF-16 comme son wchar_t de codage, et parce que UTF-16 utilise des paires de substitution pour représenter codepoints plus grand que U+FFFF, ce qui signifie que UTF-16 n'est pas satisfait aux exigences pour l' __STDC_ISO_10646__.

Pour la plate-forme de code spécifique wchar_t peut-être plus utile. Il est essentiellement nécessaire sur Windows (par exemple, certains fichiers ne peuvent simplement pas être ouvert sans l'aide de wchar_t les noms de fichiers), si Windows est la seule plate-forme où cela est vrai pour autant que je sais (donc peut-être que nous pouvons penser de wchar_t comme "Windows_char_t').

Avec le recul, wchar_t est clairement pas utile pour simplifier le traitement de texte, ou comme stockage pour les paramètres régionaux de texte indépendant. Code Portable ne devrait pas tenter de l'utiliser à ces fins.

-2voto

Raphael R. Points 3033

Pour autant que je sais, C++ fournit pas de méthodes standard pour convertir de ou UTF-32. Toutefois, pour l'UTF-16, il y a les méthodes mbstowcs (Multi-Octets de Large chaîne de caractères), et à l'inverse, wcstombs.

Si vous avez besoin d'UTF-32 trop, vous avez besoin d' iconv, qui est dans POSIX 2001, mais pas en C standard, de sorte que sur Windows, vous aurez besoin d'un remplacement, comme libiconv.

Voici un exemple sur la façon d'utiliser mbstowcs:

#include <string>
#include <iostream>
#include <stdlib.h>

using namespace std;

wstring widestring(const string &text);

int main()
{
  string 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 qui va comme ceci:

string mbstring(const wstring &text)
{
  string result;
  result.resize(text.length());
  wcstombs(&result[0], &text[0], text.length());
  return result;
}

Pinailler: Oui, je sais, la taille de wchar_t est définie par l'implémentation, de sorte qu'il pourrait être de 4 Octets (UTF-32). Cependant, je ne sais pas un compilateur qui le fait.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X