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

Langage C++ Discussion :

comparer 2 variables de type string contenant des caractères étendus, (UTF8 ?)


Sujet :

Langage C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut comparer 2 variables de type string contenant des caractères étendus, (UTF8 ?)
    Bonjour,

    Je cherche à comparer deux variables de type std::string, qui doivent contenir du vocabulaire français (mots, phrases)... donc des accents.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    bool isEqual = (recognized == str_sentence)?true:false;


    La condition n'est jamais vérifiée.
    En bouclant sur chaque élément, pour les 2 variables, je m'aperçois:

    - qu'elles n'ont pas la même taille.
    - variable 1 : le code hexadécimal de la lettre 'è' est grand! (0xFFFFFFE8). Tout ces FF ne me disent rien de bon (4 octets?)
    - variable 2 : que cette même lettre 'è' semble codée sur 2 indices (8 octets?)




    Si la chaine à comparer est "allume la lumière", voilà ce que j'obtiens sur la sortie standard:




    [item index] : [caractère affiché] --> [représentation hexadécimal]


    - variable 1 : string recognized -

    0 : a --> 61
    1 : l --> 6c
    2 : l --> 6c
    3 : u --> 75
    4 : m --> 6d
    5 : e --> 65
    6 : --> 20
    7 : l --> 6c
    8 : a --> 61
    9 : --> 20
    10 : l --> 6c
    11 : u --> 75
    12 : m --> 6d
    13 : i --> 69
    14 : --> ffffffe8
    15 : r --> 72
    16 : e --> 65




    - variable 2 : string str_sentence -

    0 : a --> 61
    1 : l --> 6c
    2 : l --> 6c
    3 : u --> 75
    4 : m --> 6d
    5 : e --> 65
    6 : --> 20
    7 : l --> 6c
    8 : a --> 61
    9 : --> 20
    10 : l --> 6c
    11 : u --> 75
    12 : m --> 6d
    13 : i --> 69
    14 : --> ffffffc3
    15 : --> ffffffa8
    16 : r --> 72
    17 : e --> 65



    La première variable est déclarée et initialisée comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const char* hypothese = ps_get_hyp(ps, NULL, &uttid);  // Une fonction de la librairie pocketsphinx qui renvoie un const char *
    string recognized(hypothese);


    La seconde variable est issue du résultat d'un callback de sqlite3 qui est appelé autant de fois qu'il y a d'enregistrements retournés par la requête ("SELECT * FROM table WHERE ...")
    D'après la documentation de SQLite, le format par défaut des résultats est UTF-8

    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    struct datasBlock
    {
        vector< vector<string> > rows;
    };
     
     
     
    int callback_result(void *datas, int argc, char **argv, char **azColName)
    {
     
        datasBlock *block = (datasBlock*)datas;
     
        int colCount = argc;
     
        if (colCount < 1)
            return 1;
     
        // crée un enregistrement en mémoire
        vector<string> tmpRow;
        for (int i=0; i<colCount; i++)
            tmpRow.push_back(argv[i]);
     
        block->rows.push_back(tmpRow);
     
        return 0;
    }




    Pensez vous qu'il y ait quelque chose comme de l'UTF-16 ici que je devrais peut être d'abord convertir en UTF-8 avant de faire le test?

    J'ai fouillé les classes string, wstring et tenté des conversion (mbstowcs et wcstombs), mais sans succès.
    Et même vu quelque chose au sujet de la "locale"...
    Certains parlent de la libiconv...

    En fin de compte je crois que je suis parti dans tous les sens...
    Auriez vous quelques pistes à me donner?

    Merci pour vos réponses


    PS:

    Je ne comprend pas comment un élément/indice de type string peut contenir une si grande valeur vu que string se compose de <char> et que sizeof(char) vaut normalement toujours 1 octet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef basic_string<char>    string;   /// A string of @c char



    Quelques précisions:
    Mon OS est Linux UBuntu 12.04 LTS, mais je prévois également de faire tourner le code sous Windows.
    J'utilise Qt, mais ne souhaite pas utiliser la classe QString à cet endroit du programme.

  2. #2
    Membre éprouvé Avatar de fenkys
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    376
    Détails du profil
    Informations personnelles :
    Âge : 57
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 376
    Points : 1 054
    Points
    1 054
    Par défaut
    Bonjour,

    Tu as des problèmes de conversion automatiques des valeurs contenues dans tes chaines. Fait attention à la façon dont tu remplis tes variables.

    Le caractères 0xE8 (è) est codé 0xC3 0xA8 en utf8. Si tu utilises des signed char, ces valeurs représentes des nombres négatifs. Tu as quelques par une conversion en signed int, le caractère négatif du nombre est conservé, et donc des ff sont rajouté devant. Tu compares donc une chaine à la baselatin1 et une utf8 avec une conversion signée de char en int en cours de route.

    En clair, vérifie tous les types que tu utilises, les affectations et les conversions.

    A la base, n'oublie pas que le type string, même s'il peut en contenir, n'est pas fait pour gérer l'utf8. Un certain nombre de fonctions membre ne vont pas fonctionner normalement (length(), find_first_of, ...) . Personnellement je travaille en wstring et convertit en utf8 qu'au dernier moment.


    Fenkys

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut
    Je crois que le problème venait de ma façon d'afficher les résultats:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for (size_t i=0; i<str_sentence.length(); i++)
    	cout << i << " : " << str_sentence.at(i) << " --> " << std::hex << int(str_sentence.at(i)) << endl;
    J'ai tenté un printf, et là ça marche:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    for (size_t i=0; i<str_sentence.length(); i++)
            printf("%d : %c --> %x\n", i, (unsigned char)str_sentence.at(i), (unsigned char)str_sentence.at(i));
    Il y a donc plus qu'à convertir ma chaine ISO8859-1 en UTF-8 et me familiariser avec les wstring

    Merci de m'avoir remis sur le droit chemin

  4. #4
    Membre éprouvé Avatar de fenkys
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    376
    Détails du profil
    Informations personnelles :
    Âge : 57
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 376
    Points : 1 054
    Points
    1 054
    Par défaut
    Ton code fait bien ce que j'avais dit dans mes explications:
    - str_sentence.at(i) affiche un char (un byte)
    - int(str_sentence.at(i)) affiche un int (en environnement i386 : 4 bytes)
    Les deux étant négatifs, ils n'ont pas la même représentation à l'ecran.


    Tu devrais apprendre à utiliser correctement les iostream plutôt que de revenir au printf du C. C'est incroyablement plus puissant.

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Citation Envoyé par fenkys Voir le message
    Tu devrais apprendre à utiliser correctement les iostream plutôt que de revenir au printf du C. C'est incroyablement plus puissant.
    Sauf dès que tu veux que ton programme puisse marcher en plusieurs langues (mais même le printf() étendu pour l'i18n est très maladroit pour cela, je l'admets).

    Ce code C++ devrait éviter les problèmes liés aux caractères "négatifs":
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (size_t i=0; i<str_sentence.length(); i++)
    	cout << i << " : " << str_sentence.at(i) << " --> " << std::hex << static_cast<int>(static_cast<unsigned char>(str_sentence.at(i))) << endl;

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    47
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 47
    Points : 41
    Points
    41
    Par défaut
    Médinoc, merci pour ton retour.
    Ton code fonctionne parfaitement bien.

    J'ai compris le principe du double cast.
    Une première conversion en unsigned char pour un codage sur 8 bits.
    Et la seconde pour convertir en entier avant de passer tout ça à cout.

    Pour conclure sur ce topic, j'ai décidé de ne pas me lancer tout de suite dans l'UTF-8.
    Comme mes chaînes à traiter sont essentiellement en français, et en anglais, j'ai décidé de rester en ISO8859-1 (Latin-1)

    J'utilise la fonction suivante pour convertir les caractères UTF-8 en Latin-1.


    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    std::string UTF8toISO8859_1(const char * in)
    {
        std::string out;
        if (in == NULL)
            return out;
     
        unsigned int codepoint;
        while (*in != 0)
        {
            unsigned char ch = static_cast<unsigned char>(*in);
            if (ch <= 0x7f)
                codepoint = ch;
            else if (ch <= 0xbf)
                codepoint = (codepoint << 6) | (ch & 0x3f);
            else if (ch <= 0xdf)
                codepoint = ch & 0x1f;
            else if (ch <= 0xef)
                codepoint = ch & 0x0f;
            else
                codepoint = ch & 0x07;
            ++in;
            if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
            {
                if (codepoint <= 255)
                {
                    out.append(1, static_cast<char>(codepoint));
                }
                else
                {
                    // do whatever you want for out-of-bounds characters
                }
            }
        }
        return out;
    }

    Maintenant la comparaison fonctionne correctement.

    Encore un grand merci à vous

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

Discussions similaires

  1. [Débutant] Comparer un textbox avec un variable de type string
    Par DavidLarochelle dans le forum C#
    Réponses: 3
    Dernier message: 15/02/2013, 17h18
  2. Compilation des variables de type string
    Par cs_ntd dans le forum C#
    Réponses: 7
    Dernier message: 05/07/2008, 14h52
  3. comparer 2 variables de type string
    Par kohsaka dans le forum C++
    Réponses: 3
    Dernier message: 21/01/2007, 18h31
  4. Des " dans une variable de type String
    Par 4lkaline dans le forum Langage
    Réponses: 6
    Dernier message: 06/11/2006, 14h20
  5. [VB] gestion des couleurs des variables de type string
    Par landry005 dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 28/03/2006, 14h36

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