IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Gérer l'encodage sous Windows


Sujet :

C++

  1. #1
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut Gérer l'encodage sous Windows
    Bonjour à tous,

    j'ai un ensemble de librairie qui fonctionne sous Windows et Linux et qui sont utilisé par des UI développée pour chaque plateforme.
    Certaines fonctions prennent en paramètre des std::string afin de les afficher ou encore des les écrires dans une base de données sqlite :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void Log(const std::string& msg );
    Sous linux pas de problème , je peux écrire des accents , du chinois , du russe, etc ... sans aucun problème.
    Sous windows en revanche c'est un autre problème puisque si le projet est en unicode je retrouve les erreurs typique d'encodage dans la chaîne finale.

    Donc le code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::string msg("éàçèù");
    Log(msg);
    fonctionne parfaitement sous Linux mais m'écrit n'importe quoi sous windows.

    Sous windows la solution semble être d'utiliser des std::wstring sauf que les librairies (cross plateforme) utilisent elle des std::string.

    En prenant par exemple les deux définitons suivantes quels sont les solutions possible pour rendre windows compatible ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void Log(const std::string& msg );
    std::string GetLog();
    Merci
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Et si c'était l'affichage qui échouait, et pas l'encodage dans la string?
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Cela me semble normal que tu aies des problèmes avec std::string sous Windows: tu es tributaire du code page

    Il faut échapper tes caractères pour forcer l'UTF-8.
    Il faut coder un truc comme cela
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       std::string msg("\xC3\xA9\xC3\xA0\xC3\xA7\xC3\xA8\xC3\xB9");
    //  std::string msg("\xC3""\xA9""\xC3""\xA0""\xC3""\xA7""\xC3""\xA8""\xC3""\xB9");

  4. #4
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    tu as un excellent post sur stackoverflow: http://stackoverflow.com/questions/4...g-vs-stdstring
    Il décrit bien les différences UNIX / Windows. En résumé, sous UNIX, travailler avec des char revient souvent, sans même qu'on s'en rende compte, à travailler en unicode. En Windows, pour des raisons de rétro-compatibilité, ce sont les caractéristiques locales (ex: français, russe, etc.) qui passent en premier. La conclusion générale:
    Conclusion
    1. Quand utiliser wstring plutôt que string?
    sous linux - presque jamais
    sous windows - presque toujours
    en code portable - cela dépend des outils à disposition
    Du coup peut-être faudrait-il que tu changes de type selon la plate-forme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #ifdef __WINDOWS_XX
    typedef wstring string
    #endif

  5. #5
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut
    Citation Envoyé par foetus Voir le message
    Cela me semble normal que tu aies des problèmes avec std::string sous Windows: tu es tributaire du code page

    Il faut échapper tes caractères pour forcer l'UTF-8.
    Il faut coder un truc comme cela
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       std::string msg("\xC3\xA9\xC3\xA0\xC3\xA7\xC3\xA8\xC3\xB9");
    //  std::string msg("\xC3""\xA9""\xC3""\xA0""\xC3""\xA7""\xC3""\xA8""\xC3""\xB9");
    Ouais c'est mort

    Citation Envoyé par stendhal666 Voir le message
    tu as un excellent post sur stackoverflow: http://stackoverflow.com/questions/4...g-vs-stdstring
    J'avais déjà lu cet article qui grosso modo dit string sous linux et wstring sous windows ^^ Ce qui ne m'avance pas des masses.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #ifdef __WINDOWS_XX
    typedef wstring string
    #endif
    C'est envisageable dans le cas ou on peut aller modifier la librairie utilisée ce qui n'est pas toujours le cas.

    J'ai avancé un peu grace à 2 fonctions de conversion :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    wstring s2ws(const std::string& str)
    {
        typedef std::codecvt_utf8<wchar_t> convert_typeX;
        std::wstring_convert<convert_typeX, wchar_t> converterX;
     
        return converterX.from_bytes(str);
    }
     
    string ws2s(const std::wstring& wstr)
    {
        typedef std::codecvt_utf8<wchar_t> convert_typeX;
        std::wstring_convert<convert_typeX, wchar_t> converterX;
     
        return converterX.to_bytes(wstr);
    }
    Du coup ça me permet sous windows de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::wstring msg("éàçèù");
    Log(ws2s(msg));
    Ce qui fonctionne bien tant que je reste dans l'alphabet latin. Alors qu'avant même les accent ne marchait pas.
    En revanche dès que je passe sur du cyrillique ou du chinois je me retrouve avec 2 ?? en lieu et place du caractère

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::wstring msg("测试");
    Log(ws2s(msg)); // Log ??
    Ce qui m'intrigue c'est que le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CString test("测试");
    AfxMessageBox(test);
    M'affiche également "??" J'ai bien essayer d'ajouter un setlocale(LC_ALL,"chinese") sans succès

    Une idée ?
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    C'est mort mais tu échappes quand même tes caractères

    Sinon cela ne fonctionne pas parce que pour échapper les caractères il faut utiliser soit \x soit \u soit \U soit autre chose.

    Je n'ai d'ailleurs rien trouvé d'officiel à ce sujet

    Édit: Programming with Unicode

    It’s also possible to write the value in octal (e.g. '\033' = 27) or hexadecimal (e.g. '\x20' = 32)

    wchar_t: A literal character is written between apostrophes with the L prefix, e.g. L'a'. As byte literal, it’s possible to write control character with an backslash and a character with its value in octal or hexadecimal. For codes bigger than 255, '\uHHHH' syntax can be used. For codes bigger than 65535, '\UHHHHHHHH' syntax can be used with 32 bits wchar_t.

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Le gros problème sous Windows, est double:
    1. La console. Elle est assez pourrie côté accents en C++, car même à supposer qu'on arrive à y écrire correctement (ce qui n'est vraiment pas gagné avec les iostreams) elle reste limitée aux caractères supportés par l'encodage IBM-850 à moins qu'on règle sa police sur Lucida Console.
    2. Les fichiers. À la base de C++, il n'y a pas vraiment de moyen d'écrire des fichiers en choisissant leur encodage (écrire une wstring ne sert à rien si le code convertit d'abord la wstring en Windows-1252 avant d'écrire).
      Visual Studio 2005 a apporté un workaround pour écrire des fichiers texte avec des encodages Unicode (au moins UTF-16LE et UTF-8), mais j'ai bien peur que cela soit limité aux flux C. Et C++, bien qu'ayant un support "legacy" des flux C, n'offre aucune facilité dans sa bibliothèque standard pour avoir un flux C++ écrivant sur un flux C: Pour ça tu te retrouves à implémenter toi-même une classe dérivant de basic_streambuf<> pour ça.


    Edit: Le standard C++ a également son lot de facteurs aggravants, notamment son support des fichiers binaires, qui n'est en fait qu'un bricolage maladroit (et traître) bâti sur les fichiers texte. Même des trucs récents comme les générateurs pseudo-aléatoires ne peuvent sérialiser leur état interne que sous forme de texte!

    Ce que je suggérerais, c'est voir comment les iostreams de Linux réagissent aux wstrings. Si le résultat est acceptable (comme une conversion en UTF-8), on les utilisera aussi sous Windows et on avisera pour écrire en unicode dans des fichiers ou la console (avec des classes dérivées de basic_streambuf).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ce que je suggérerais, c'est voir comment les iostreams de Linux réagissent aux wstrings. Si le résultat est acceptable (comme une conversion en UTF-8), on les utilisera aussi sous Windows et on avisera pour écrire en unicode dans des fichiers ou la console (avec des classes dérivées de basic_streambuf).
    Il y a cette bibliothèque UTF8-CPP assez simple que l'on peut soit utiliser soit s'inspirer pour faire les conversions UTF8 <-> UTF16 (ce n'est pas compliqué)

  9. #9
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut
    Merci pour vos réponses.
    Le sujet est loin d'être évident à priori.

    Je suis arrivé à une solution qui me convient pour le moment à savoir :

    Toutes mes librairies utilisent std::string.
    Sous linux pas de problème tout fonctionne bien.

    Sous windows j'utilise des std::string ET mes fichiers (cpp,h) sont encodé en utf8 (fichier > option d'enregistrement avancée sous VS2015).
    J'obtient le résultat escompté en terme d'écriture dans une base sqlite ou dans un fichier texte. Le fichier se retrouve du coup avec l'encodage UTF8 sans bom.

    Pour ce qui est de l'affichage dans MFC je fait ca :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::string msg("ma chaine en russe/chinois/japonais ...");
    AfxMessageBox(CA2CT(msg.c_str(),CP_UTF8));
    C'est pas bien pratique mais ça semble marcher correctement
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Encodage sous windows
    Par nuts62 dans le forum Général Java
    Réponses: 3
    Dernier message: 26/10/2010, 15h01
  2. Problème d'encodage sous Windows / Linux
    Par robert_trudel dans le forum Eclipse Java
    Réponses: 3
    Dernier message: 29/09/2009, 17h30
  3. Outils graphique sous windows pour gérer les bases SQLite
    Par Louis Griffont dans le forum SQLite
    Réponses: 8
    Dernier message: 21/04/2008, 14h09
  4. Comment gérer des reps sous Windows & Linux ?
    Par Sylver--- dans le forum Langage
    Réponses: 4
    Dernier message: 02/06/2007, 13h04
  5. [Utilisation] Probleme encodage sous windows
    Par tittoto dans le forum Subversion
    Réponses: 2
    Dernier message: 28/05/2007, 09h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo