2009-08-30 15 views
2

Dans un projet, toutes les chaînes internes sont conservées au format utf-8. Le projet est porté sur Linux et Windows. Il y a un besoin pour une fonctionnalité to_lower maintenant.Facette de type C++ pour UTF-8 dans la combinaison

Sur POSIX OS, je pourrais utiliser std :: ctype_byname ("ru_RU.UTF-8"). Mais avec g ++ (Debian 4.3.4-1), ctype :: tolower() ne reconnaît pas les caractères russes UTF-8 (le texte latin est en minuscule). Sous Windows, la bibliothèque standard de mingw lève l'exception "std :: runtime_error: locale :: facet :: _ S_create_c_locale name non valide" lorsque j'essaie de construire std :: ctype_byname avec l'argument "ru_RU.UTF-8". Comment j'implémente/trouve std :: ctype pour utf-8 sur Windows?

Le projet dépend déjà de libiconv (la facette codecvt est basée dessus), mais je ne vois pas de moyen évident d'implémenter to_lower avec.

+0

La raison pour laquelle ctype ne peut pas gérer les codages multi-octets est qu'il ne peut pas modifier la taille du symbole. Les conversions Utf-8 doivent être gérées par une interface différente. Désolé, je n'ai pas pu l'obtenir plus tôt. – Basilevs

+0

De ma mémoire 'glibc' génère des informations pour différents paramètres régionaux. Il se peut que les fichiers de paramètres régionaux pertinents n'aient pas été installés sur la machine en question. – user1095108

Répondre

2

Si tout ce que vous avez besoin est to_lower pour les caractères cyrilliques, vous pouvez écrire une fonction par vous-même.

АБВГДЕЖ in UTF8 D0 90 D0 91 D0 92 D0 93 D0 94 D0 95 D0 96 0A 
абвгдеж in UTF8 D0 B0 D0 B1 D0 B2 D0 B3 D0 B4 D0 B5 D0 B6 0A

Mais n'oubliez pas que UTF8 est un codage multi-octets.

Vous pouvez également essayer de convertir une chaîne de UTF8 en wchar_t (en utilisant libiconv) et utiliser la fonction Windows spécifique pour implémenter to_lower.

0

Il y a un certain STL (comme celui d'Apache - STDCXX, par exemple) qui vient avec plusieurs locales. Mais dans d'autres situations, les paramètres régionaux dépendent uniquement du système.

Si vous pouviez utiliser le nom "ru_RU.UTF-8" sur un système d'exploitation, cela ne signifie pas que les autres systèmes ont le même nom pour cette locale. Debian et Windows ont probablement d'autres noms et c'est la raison pour laquelle vous avez une exception d'exécution.

Vous devez auparavant installer les paramètres régionaux souhaités sur le système. Ou utilisez une STL qui a déjà cette locale.

Mes cents ...

+0

Je suis sûr que Windows sait comment gérer l'encodage utf-8. J'ai même obtenu le numéro de page de code - 65001. La question est - quel nom de locale devrait être employé dans mon cas. De toute façon, il semble que j'essaie de faire une chose fondamentalement fausse (voir le commentaire à la question). – Basilevs

+0

Cette page vous aide-t-elle: http://msdn.microsoft.com/fr-fr/library/dd373814(VS.85).aspx? – dudewat

3

Essayez d'utiliser STLport

 
    Here is a description of how you can use STLport to read/write utf8 files. 
utf8 is a way of encoding wide characters. As so, management of encoding in 
the C++ Standard library is handle by the codecvt locale facet which is part 
of the ctype category. However utf8 only describe how encoding must be 
performed, it cannot be used to classify characters so it is not enough info 
to know how to generate the whole ctype category facets of a locale 
instance. 

In C++ it means that the following code will throw an exception to 
signal that creation failed: 

#include 
// Will throw a std::runtime_error exception. 
std::locale loc(".utf8"); 

For the same reason building a locale with the ctype facets based on 
UTF8 is also wrong: 

// Will throw a std::runtime_error exception: 
std::locale loc(locale::classic(), ".utf8", std::locale::ctype); 

The only solution to get a locale instance that will handle utf8 encoding 
is to specifically signal that the codecvt facet should be based on utf8 
encoding: 

// Will succeed if there is necessary platform support. 
locale loc(locale::classic(), new codecvt_byname(".utf8")); 

    Once you have obtain a locale instance you can inject it in a file stream to 
read/write utf8 files: 

std::fstream fstr("file.utf8"); 
fstr.imbue(loc); 

You can also access the facet directly to perform utf8 encoding/decoding operations: 

typedef std::codecvt codecvt_t; 
const codecvt_t& encoding = use_facet(loc); 

Notes: 

1. The dot ('.') is mandatory in front of utf8. This is a POSIX convention, locale 
names have the following format: 
language[_country[.encoding]] 

Ex: 'fr_FR' 
    'french' 
    'ru_RU.koi8r' 

2. utf8 encoding is only supported for the moment under Windows. The less common 
utf7 encoding is also supported. 
+0

Tout cela peut être fait dans linux ou windows sans STLport. Il n'y a pas de ctype dans votre exemple. Et votre codecvt convertirait utf-8 en encodage différent (CP ????, ou WCHAR_T) alors que ma question portait sur utf-8 comme représentation interne. – Basilevs