11
votes

Comment obtenir STL STD :: String pour travailler avec Unicode sur Windows?

chez mon entreprise, nous avons une bibliothèque de plate-forme transversale (Linux & Windows) contenant notre propre extension de la STL STD :: String, cette classe fournit toutes sortes de fonctionnalités au-dessus de la chaîne; Split, format, to / depuis base64, etc. Récemment, nous avons reçu l'obligation de faire cette chaîne unicode "amical" fondamentalement, il doit soutenir des personnages de chinois, japonais, arabe, etc. Après la recherche initiale, cela semble bien sur le côté Linux Comme tout est intrinsèquement utf-8, mais je rencontre des problèmes avec le côté Windows; Y a-t-il un tour pour obtenir la STL STD :: String pour travailler comme UTF-8 sur Windows? Est-ce même possible? Y a-t-il une meilleure façon? Idéalement, nous resterions nous-mêmes basé sur la STD :: String car c'est ce que la classe de chaîne est basée sur Linux.

Merci,


3 commentaires

Voir cette question, a une réponse très approfondie: Stackoverflow.com/Questtions/402283 / stdwstring-vs-stdstring


Mai ou peut ne pas aider (ne peut pas le tester moi-même): SetLocale (LC_CTYPE, "EN_US.UTF-8") cplusplus.com/reference/clibrary/clocale/setlocale Cela définit le codage pour l'ensemble de l'application à UTF-8


Regardez ma réponse ici:

9 Réponses :


4
votes

Avez-vous regardé std :: wstring ? C'est une version de std :: basique_string pour wchar_t plutôt que le char que std :: string utilise. < / p>


1 commentaires

Ce n'est pas la même chose que Unicode sur Windows..ethwing n'a pas de soutien réel dans la STL ..



7
votes

Mettre en place des points de code UTF-8 dans un std :: string devrait aller bien quelle que soit la plate-forme. Le problème sous Windows est que presque rien d'autre n'attend ou ne fonctionne pas avec UTF-8 - il attend et fonctionne avec UTF-16. Vous pouvez passer à un std :: wstring qui stockera UTF-16 (au moins sur la plupart des compilateurs Windows) ou vous pouvez écrire d'autres routines qui accepteront UTF-8 (probablement en convertissant à l'UTF-16 , puis passant à travers le système d'exploitation).


4 commentaires

Essayé d'utiliser Wstring, mais l'application semble être incapable de rendre les caractères Unicode que je testais avec, "大夨 天太夫", donc pas sûr de quoi faire de cela? Y a-t-il des fenêtres spéciales "Voodoo" que je dois travailler pour que Wstring fonctionne pour travailler?


@Nsa, vous devez sélectionner une police qui inclut les caractères que vous souhaitez afficher. Très peu de polices ont une grande partie des points de code Unicode couverts.


@NSA - Assurez-vous que "Support de langues Est" activé dans le panneau de contrôle -> Paramètres régionaux et linguistiques. Vous pouvez également utiliser une police qui manque ces caractères.


@NSA: Cela dépend. Si vous essayez d'utiliser cout ou wcout , c'est à peu près une catastrophe. Si vous passez le contenu d'un wstring directement sur une fonction Windows, les choses sont beaucoup plus simples ( printf et un tel travail aussi). À partir de là, il s'agit principalement d'assurer que la police que vous utilisez peut afficher tous les caractères que vous aimez.



13
votes

Il y a plusieurs idées fausses dans votre question.

  • ni c ++ ni l'affaire STL avec les codages.

  • std :: string est essentiellement une chaîne de octets , pas caractères . Donc, vous ne devriez pas avoir de problème de farce UTF-8 encodé unicode. Toutefois, gardez à l'esprit que toutes les fonctions string fonctionnent également sur des octets, donc mystring.length () vous donnera le nombre d'octets et non le nombre de caractères.

  • linux est pas intrinsèquement utf-8. La plupart des distributions sont de nos jours par défaut de l'UTF-8, mais il ne faut pas s'appuyer sur.


4 commentaires

Si STL ne connaît rien de codages, qu'est-ce que STD :: locale alors?


Lieu. Qui n'est pas la même chose que le codage.


Mais le nom de la locale peut contenir le nom d'un codage, par ex. EN_US-UTF8, donc il me semble faux de dire "STL ne sait pas rien sur les codages".


@Paniq: std :: locale appartient au côté iOSTream de la bibliothèque standard, pas du côté STL de la bibliothèque standard. STD :: String n'a pas démarré comme une classe STL, mais a été faite de type STL lorsque la STL a été ajoutée au projet C ++ 98 (en 1996).



3
votes

Non, il n'ya aucun moyen de traiter Windows Traiter des chaînes "étroites" comme UTF-8.

Voici ce qui fonctionne le mieux pour moi dans cette situation (application multi-plateformes contenant des bâtiments Windows et Linux).

  • Utilisez STD :: String dans une partie multiplate-forme du code. Supposons qu'il contient toujours des chaînes UTF-8.
  • Dans la partie Windows du code, utilisez explicitement des versions "larges" de Windows API, c'est-à-dire Ecrire par exemple. Createfilew au lieu de Createfile. Cela permet d'éviter la dépendance à la configuration du système de construction.
  • dans la couche d'abstraction PlatFrom, convertit entre UTF-8 et UTF-16, le cas échéant (MultiByteTowidechar / widechartomultibyte).

    Autres approches que j'ai essayées mais n'aime pas beaucoup:

    • TypeDEF STD :: basique_string TString; utilise ensuite TString dans le code d'entreprise. Les enveloppes / surcharges peuvent être faites pour rationaliser la conversion entre STD :: String et STD :: TString, mais il ajoute toujours beaucoup de douleur.
    • Utilisez std :: wstring partout. N'ajoute pas beaucoup depuis wchar_t 16 bits sous Windows, vous devez donc vous limiter à vous limiter à BMP ou à accéder à de nombreuses complications pour rendre le code traite avec une plate-forme multiples Unicode. Dans ce dernier cas, tous les avantages sur UTF-8 s'évaporent.
    • Utilisez ATL / WTL / MFC CSSTRING dans la partie spécifique à la platine; Utilisez std :: chaîne dans la partie transversale. C'est en fait une variante de ce que je recommande ci-dessus. cstring est dans de nombreux aspects supérieurs à std :: string (à mon avis). Mais il introduit une dépendance supplémentaire et donc pas toujours acceptable ou commode.

4 commentaires

Utiliser STD :: Wstring ne vous limite pas à la BMP. La gamme complète de points de codes Unicode peut être codée dans UTF-16, en utilisant des substituts, le cas échéant, et STD :: Wstring peut contenir une chaîne codée UTF-16.


@Remy - Bien sûr. C'est ce que je voulais dire par «ou aller à beaucoup de complications pour rendre le code traitant de la plate-forme continue Unicode». Sur Linux, wchar_t peut contenir tout le code de code de code; Sous Windows, il ne peut pas. Vous devez donc utiliser la compilation conditionnelle et les trucs. Et vous n'avez plus la belle propriété de "une cellule == un caractère" plus. Alors pourquoi pas seulement utiliser UTF-8?


Essayez std :: basic_string (ou similaire) Pour forcer une chaîne codée UTF-16 sur toutes les plates-formes sans s'appuyer sur la taille d'octets de WCHAR_T. De plus, vous n'avez pas de garantie «une cellule = une Char» dans UTF-8, car l'UTF-8 code d'un point de code Unicode en utilisant entre 1 et 4 CodeUnits, tandis que UTF-16 utilise toujours 2 CodeUnits. Donc, si quelque chose, UTF-16 peut parfois être plus facile à travailler avec UTF-8. Le principal avantage de l'UTF-8 est la compatibilité à l'envers avec ASCII. Pour les codépoints en dehors de l'ASCII, vous devez faire face aux codages Unicode, ainsi que pour les codépoints au-dessus de U + 07FF, UTF-8 utilise plus d'espace de stockage que UTF-16.


@Remy - Je n'ai jamais impliqué qu'il y a une garantie "une cellule = une Char" dans UTF-8. S'il vous plaît lire plus attentivement. Utilisation de std :: basic_string apportera les inconvénients de la manipulation UTF16 à toutes les plateformes; Pourquoi le faire si tu n'es pas obligé? En outre, cela ne fonctionnera pas avec STD :: Streams sur Windows (sur certains compilateurs au moins).



3
votes

Si vous voulez éviter les maux de tête, n'utilisez pas du tout les types de chaîne stl. C ++ sait rien sur Unicode ou des codages, afin d'être portable, il est préférable d'utiliser une bibliothèque adaptée au support Unicode, par exemple. la bibliothèque ICU. L'ICU utilise des chaînes UTF-16 par défaut, donc aucune conversion n'est requise et prend en charge les conversions vers de nombreux autres codages importants tels que UTF-8. Essayez également d'utiliser des bibliothèques inter-plateformes telles que Boost.FileSystem pour des choses comme des manipulations de chemin ( boost :: wpath ). Évitez std :: string et std :: FRStream .


0 commentaires

1
votes

dans la bibliothèque d'exécution de Windows API et C, PARAMETERS DE CHAR * est interprété comme encodé dans la page "ANSI". Le problème est que UF-8 n'est pas pris en charge comme une page de code ANSI , qui Je trouve incroyablement ennuyeux .

Je suis dans une situation similaire, étant au milieu du logiciel de portage de Windows à Linux tout en le faisant savoir unicode. L'approche que nous avons prise est:

  • Utilisez UTF-8 comme codage par défaut pour les chaînes.
  • dans le code spécifique à Windows, appelez toujours la version "W" des fonctions, convertissant des arguments de chaîne entre UTF-8 et UTF-16 si nécessaire.

    Ceci est également L'approche POCO a pris .


1 commentaires

UTF-8 est partiellement supporté en tant que page de code ANSI et s'appelle Windows CP65001. Il a des problèmes qui ne sont pas encore repassés, bien que comme un bogue dans le fichier Wrystfile () API.



10
votes

Oui - en étant plus conscient des locaux et des codages.

Windows a deux appels de fonctions pour tout ce qui nécessite un texte, un Foobara () et un Foobarw (). Les fonctions * W () prennent des chaînes codées UTF-16, le * A () prend des chaînes dans le codépage actuel. Toutefois, Windows ne prend pas en charge une page de code UTF-8, vous ne pouvez donc pas l'utiliser directement dans ce sens avec les fonctions * A () et ne voudriez pas dépendre de celle-ci par les utilisateurs. Si vous souhaitez "Unicode" sous Windows, utilisez les fonctions UNICODE-CAPABLE (* W). Il y a des tutoriels là-bas, Googling "Unicode Windows Tutorial" devrait vous en obtenir.

Si vous stockez des données UTF-8 dans une STD :: String, puis avant de la transmettre à Windows, convertissez-la en UTF-16 (Windows fournit des fonctions pour le faire), puis transmettez-la à Windows. < / p>

Beaucoup de ces problèmes découlent de C / C ++ étant généralement encodés-agnostiques. Char n'est pas vraiment un personnage, c'est juste un type intégral. Même en utilisant des tableaux Char pour stocker les données UTF-8, vous pouvez vous mettre en difficulté si vous devez accéder aux unités de code individuelles, car Char SIGNÉ-NESS est laissé non défini par le normes. Une déclaration comme str [x] <0x80 pour vérifier que les caractères de plusieurs octets peuvent introduire rapidement un bug. (Cette déclaration est toujours vraie si Char est signé.) Une unité de code UTF-8 est un type intégré non signé avec une plage de 0 à 255. Cette carte vers le type C de uint8_t exactement, bien que non signé Char fonctionne également. Idéalement, je ferais une chaîne UTF-8 une chaîne de uint8_t s, mais en raison d'anciennes API, ceci est rarement fait.

Certaines personnes ont recommandé wchar_t , réclamant qu'il s'agit d'être "un type de caractère unicode" ou quelque chose comme ça. Encore une fois, la norme est tout aussi agnostique qu'auparavant, car c est censé travailler n'importe où et n'importe où pourrait ne pas utiliser Unicode. Ainsi, wchar_t n'est plus unicode que char . Les états standard:

qui est un type d'entier dont la plage de valeurs peut représenter des codes distincts pour tous les membres du plus grand jeu de caractères étendu spécifié parmi les locaux pris en charge

in Linux, un wchart_t représente une unité de code / code de code UTF-32. C'est donc 4 octets. Cependant, sous Windows, c'est une unité de code UTF-16 et n'est que 2 octets. (Ce qui, j'aurais dit que je ne serais pas conforme à ce qui précède, car 2 octets ne peuvent pas représenter tous d'unicode, mais c'est ainsi que cela fonctionne.) Cette différence de taille et la différence de codage de données, met clairement une souche sur la portabilité. La norme UNICODE elle-même recommande contre wchar_t si vous avez besoin de portabilité. (§5.2)

la leçon de fin: Je trouve plus facile à stocker toutes mes données dans un format bien déclaré. (Typiquement utf-8, généralement dans STD :: String's, mais j'aimerais vraiment quelque chose de mieux.) La chose importante ici n'est pas la partie UTF-8, mais plutôt, je sais que mes cordes sont UTF-8. Si je les transmettes à une autre API, je dois aussi savoir que l'API attend des chaînes UTF-8. Si ce n'est pas le cas, je dois les convertir. (Ainsi, si je parle à l'API de la fenêtre, je dois convertir des chaînes en UTF-16.) Une chaîne de texte UTF-8 est une chaîne de texte "orange" et une chaîne de texte "latin1" est une "pomme". Un tableau char qui ne sait pas ce qui codant dans son encodage est une recette pour la catastrophe.


0 commentaires

0
votes

Il dépend vraiment de la plate-forme, Unicode est mal à la tête. Dépend du compilateur que vous utilisez. Pour les plus anciens de la SP (VS2010 ou plus), vous auriez besoin d'une API d'utilisation décrite dans MSDN

pour VS2015 P>

std::string _old = u8"D:\\Folder\\This \xe2\x80\x93 by ABC.txt";
std::cout << _old.data();


0 commentaires

0
votes

Vous devez envisager d'utiliser qstring et qbytearray, il a un bon support unicode


0 commentaires