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 :

compteur de voyelles


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 36
    Par défaut compteur de voyelles
    Bonjour,
    dans le cadre de mon master, j'ai l'exercice suivant à faire. Je dois faire un compteur de voyelles. Mon code marche très bien pour les fichiers UTF-8 mais les caractères diacrités ne sont pas reconnus pour le Latin-1, seulement les voyelles normales. Avez-vous une idée pour m'aider ? Voici mon code :
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
     
    #include <iostream> //directive qui demande au préprocesseur d'inclure le fichier du flot d'entrée et sortie standard C++
    #include <fstream> //pour lire à partir d'un fichier
    #include <string> //utilisation des objets string et ses methodes
    #include <cctype>
     
    using namespace std; //on utilise l'espace de noms de la biblioteque stantard C++
     
    int main(void) //en-tete du programme principal
    {
        //ensemble des voyelles francaises 
        string voyelles_ascii_min("aeiouy");
        string voyelle_diac_min("àâéèêëîïôœùûüÿ");
        string voyelle_diac_maj("ÀÂÉÈÊËÎÏÔŒÙÛÜŸ");
        string::size_type size_voyelles_diac = voyelle_diac_min.size();
        string::size_type size_voyelles_ascii = voyelles_ascii_min.size();
     
        string line;
        //nbvdiac = compteur de voyelles diacritées
        //nbvascii = compteur de voyelles ascii
        //nbcar = compteur de caracteres
        unsigned long nbvdiac(0), nbvascii(0), nbcar(0);
     
        //déclaration et instanciation d'un objet ifstream pour la lecture à partir d'un fichier
        ifstream text_file("fouilles_Lat9.txt");
     
        //si un probleme s'est passé à l'ouverture (fichier inéxistant...)
        if(text_file.is_open() == false)
        {
            cout << "Erreur : le fichier ne peut pas etre chargé !" << endl;
        }
        //sinon, on continue
        else
        {
            //boucle while qui s'execute tant que la fin du fichier n'est pas atteinte. On lit le fichier ligne par ligne
            while (getline(text_file, line))
            {
                //on incrémente le compteur de caracteres
                nbcar++;
     
                //on parcours chaque caractere de la ligne
                for (auto c : line)
                {
     
                    //on voit si ca match avec une voyelle
                    for (unsigned short i = 0; i < size_voyelles_diac; i++)
                    {   
                        //d'abord ascii
                        if (i < size_voyelles_ascii)
                        {
                            //si oui, on incremente le compteur et on sort de la boucle for
                            if (tolower(c) == voyelles_ascii_min[i])
                            {
                                nbvascii++;
                                break;
                            }
                        //puis diacritées
                        }
     
                        //si oui, on incremente le compteur et on sort de la boucle for
                        if (c == voyelle_diac_maj[i] || c == voyelle_diac_min[i])
                        {
                            nbvdiac++;
                            break;
                        }
                    }
     
                }
     
            }
     
            //on ferme le fichier par précaution (mais c'est dispensable)
            text_file.close();
     
            //si nbchar == 0, le fichier est vide
            if (!nbcar)
            {
                cout << "Le fichier est vide" << endl;
            }
            //sinon, on affiche le nombre de lettres vocaliques à l'écran
            else
            {
                //on divise par deux car une lettre diacritée = 2 chars
                cout << "Nombre de lettres vocaliques : " << nbvascii + (nbvdiac / 2) << endl;
            }
        }
     
        return 0; //valeur transmise au système d'exploitation indiquant que l'exécution s'est déroulée normalement
    }
    La prof a mis dans l'exercice le meme texte mais dans un fichier en utf-8 et l'autre en latin-9 et donc j'ai 2 resultats differents haha
    Merci d'avance les amis

  2. #2
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 36
    Par défaut
    J'ai trouvé la solution.
    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
     
    std::string iso_8859_1_to_utf8(std::string &str)
    {
        string strOut;
        for (std::string::iterator it = str.begin(); it != str.end(); ++it)
        {
            uint8_t ch = *it;
            if (ch < 0x80) {
                strOut.push_back(ch);
            }
            else {
                strOut.push_back(0xc0 | ch >> 6);
                strOut.push_back(0x80 | (ch & 0x3f));
            }
        }
        return strOut;
    }
    Quelqu'un peut-il m'expliquer les deux derniers push_backs svp

  3. #3
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    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 772
    Par défaut
    Citation Envoyé par DoggySmile78 Voir le message
    Quelqu'un peut-il m'expliquer les deux derniers push_backs svp
    Il y a beaucoup de choses à savoir et il faut vérifier tout ce que je dis

    L'Unicode c'est plusieurs encodages dont les + connus : UTF-8, UTF-16 et UTF-32.

    La particularité de l'UTF-8 (qui est 1 encodage qui prend 1 à 4 octets pour 1 caractère), c'est qu'il est compatible ASCII (<- encodage qui ne comprend que 127 caractères)

    L'ISO 8859 1 c'est du MBCS, appelé codepage par Microsoft dans Windows et son petit nom c'est Latin 1.
    Le but des codepages, c'est d'étendre l'encodage ASCII sur 1 ou 2 octets, pour avoir des caractères spéciaux, comme les accents en français.

    Et donc

    *) if (ch < 0x80) : il faudrait regarder la table Latin 1, mais les 127 premiers caractères c'est de l'ASCII.
    127, c'est 0x1F en hexadécimal et 128 c'est 0x80.

    *) 0xC0 | ch >> 6 (1) : avec le décalage à droite, tu supprimes les 6 bits les + à droite de l'octet le + à droite et ensuite tu ajoutes 0xC0

    *) (0x80 | (ch & 0x3F) (2) : grâce au masque 0x3F tu prends que les 6 bits les + à droite de l'octet le + à droite et ensuite tu ajoutes 0x80


    Par exemple le caractère é c'est 0x00E9 ou 0000 0000 1110 1001 en ISO 8859 1. Et donc tu auras:
    • (1) ch >> 6, soit 0000 0000 0000 0011 ou 0x0003 puis 0xC0 | qui te donne 0x00C3
    • (2) ch & 0x3F, soit 0000 0000 0010 1001 ou 0x0029 puis 0x80 | qui te donne 0x00A9


    Ce qui correspond bien à l'UTF-8 ... reste à vérifier si cette conversion fonctionne avec tous les caractères étendus.


    Citation Envoyé par DoggySmile78 Voir le message
    dans le cadre de mon master, j'ai l'exercice suivant à faire. Je dois faire un compteur de voyelles. Mon code marche très bien pour les fichiers UTF-8 mais les caractères diacrités ne sont pas reconnus pour le Latin-1, seulement les voyelles normales. Avez-vous une idée pour m'aider ?
    Il faut faire 1 compteur de voyelles par encodage (UTF-8 et Latin 1 dans ton cas)

    Et ensuite avoir 1 fonction qui essaye de trouver l'encodage :
    • pour l'Unicode il y a des règles précises pour les codes valides.
    • pour les codepages, comme ce sont des tables, il faut juste tester 2 - 3 caractères en réalité tu ne peux pas tester aussi facilement et il faut utiliser des heuristiques. Dans ton cas, tu peux dire si ce n'est pas UTF-8 c'est Latin 1

    La bibliothèque de Microsoft WinAPI par exemple, a tout ce qu'il faut.

  4. #4
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 36
    Par défaut
    Merci beaucoup foetus pour toutes ces réponses Grace à toi tout est plus clair, surtout pour les questions d'encodage. Je mets sujet résolu.
    Je vais donc faire 2 compteurs différents.

  5. #5
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    Et fais attention à ton code, un caractère UTF-8 peut être sur plusieurs char, donc dire que tu as une voyelle si un char de ta chaîne est égal à un char de ton modèle ne marche pas. Tu ne compares qu'un morceau de caractère à un morceau de caractère, il faut comparer des chaînes. La voyelle à trouvée c'est : un extrait de ligne est égal à u8"à", d'où par exemple:
    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
    constexpr const std::u8string_view  voyelles_ascii_min{ u8"aeiouy" };
    constexpr const std::u8string_view  voyelle_diac_min[]{u8"à",u8"â",u8"é",u8"è",u8"ê",u8"ë",u8"î",u8"ï",u8"ô",u8"œ",u8"ù",u8"û",u8"ü",u8"ÿ",u8"æ"};
    constexpr const std::u8string_view  voyelle_diac_maj[]{u8"À",u8"Â",u8"É",u8"È",u8"Ê",u8"Ë",u8"Î",u8"Ï",u8"Ô",u8"Œ",u8"Ù",u8"Û",u8"Ü",u8"Ÿ",u8"Æ"};
    std::u8string  ligne = u8"L'œuvre de Jean Ghÿs sur l’île de Croÿ. La sœur d'Œdipe a fini ex æquo avec un bœuf.";
    int  nb_voyelles{};
     
    // caractères ASCII
    for ( auto  c  :  ligne ) {
    	for ( auto  acar  :  voyelles_ascii_min )
    		if ( static_cast<char8_t>(tolower(static_cast<std::uint8_t>(c))) == acar ) {
    			++nb_voyelles;
    			break;
    		}
    }
     
    // caractères sur plusieurs char
    auto compter = []( std::u8string const& ligne, std::u8string_view ucar ){
    		std::size_t  nb{};
    		auto  fd = std::search( ligne.begin(), ligne.end(), ucar.begin(), ucar.end() ); // premièr
    		while ( fd != ligne.end() ) {
    			++nb;
    			fd = std::search( next(fd), ligne.end(), ucar.begin(), ucar.end() ); // les autres
    		}
    		return  nb;
    	};
    for ( auto  ucar  :  voyelle_diac_min ) {
    	nb_voyelles += compter( ligne, ucar );
    }
    for ( auto  ucar  :  voyelle_diac_maj ) {
    	nb_voyelles += compter( ligne, ucar );
    }
    endl( std::cout << "nb voyelles : " << nb_voyelles );
    On doit pouvoir faire plus simple.

  6. #6
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 36
    Par défaut
    Mais on n'a jamais vu ça en cours encore. Je suis en master de linguistique. C'est des cours pour débutants. On ne travaille qu'avec le type string pour l'instant.
    En français, les caractères ascii c'est 1 char et les diacrités 2 si j'ai bien compris ? pas plus ? Pourtant mon compteur marche...
    Je suis perdu...

  7. #7
    Expert confirmé
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 539
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 539
    Par défaut
    Citation Envoyé par DoggySmile78 Voir le message
    Mon code marche très bien pour les fichiers UTF-8 mais les caractères diacrités ne sont pas reconnus pour le Latin-1, seulement les voyelles normales. Avez-vous une idée pour m'aider ? Voici mon code :
    il faut utiliser des std::wstring
    Par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::wstring MaChaineCar(L"Les chaussettes de l'archiduchesse étaient presque sèches");
    et cela fonctionnera.
    Un truc important c'est sous Visual Studio de configurer le projet en unicode

  8. #8
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 36
    Par défaut
    Pourquoi tout fonctionne avec la fonction que j'ai trouvé alors ? Je suis perdu. On n'a vu que les string en cours et la prof ne met rien hors cours.

  9. #9
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par défaut
    Est-ce que ton prof est sous Unix ?
    Si oui, alors c'est juste un prof médiocre, qui ne sait pas que Windows et Unix gèrent différement les encodages.
    Si non, il a peut-être changé ses paramètres de console y'a un moment et oublié depuis.
    Manipuler des chaînes de caractères est difficile. Chaque OS fait sa tambouille, chaque lib rajoute la sienne aussi.
    Unix supporte unicode dans des string/char, windows doit passer par wstring/wchar_t. string/char c'est uniquement pour les caractères ASCII.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  10. #10
    Membre Expert
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    683
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 95
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 683
    Par défaut
    Bonjour,

    C'est un sujet plutôt complexe pour un débutant ! De plus, je remarque que la plupart des facilités de C++11 sont dépréciées, et ce qui reste dépend beaucoup des locales, de l'OS. La seule solution portable que je vois, hors bibliothèques tierces, c'est de travailler avec des char32_t, lire les fichiers de manière brut, convertir à la volée les séquences utf8/lat9 en utf32 ( càd en code point à stocker dans un char32_t), puis chercher leurs présences à coup de string.find(). Mais même là, ça implique des opérations binaires. Vraiment étrange cette histoire ! La page ( https://www.unicode.org/charts/ ) sera d'une grande aide.

    Citation Envoyé par DoggySmile78 Voir le message
    Pourquoi tout fonctionne avec la fonction que j'ai trouvé alors ? Je suis perdu. On n'a vu que les string en cours et la prof ne met rien hors cours.
    C'est juste une impression. C'est comme si ton code devait chercher une date, 1920, mais au lieu de chercher 1920, il cherchait 1.

  11. #11
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    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 772
    Par défaut
    Citation Envoyé par DoggySmile78 Voir le message
    pourquoi aucune voyelle diacritée n'est matché en Latin-9 (codées sur 1 octet) alors que dans le texte, il y en a 12 ?
    Si les tests ne fonctionnent pas c'est que ce n'est pas du MBCS (latin-1, latin-9, ...)
    Donc dans ton cas , il faut tout afficher en hexadécimal et vérifier les codes puisque tu connais les caractères afin de t'assurer des encodages.

    Tu t'y prends mal lorsqu'on travaille avec différents encodages, je pense que le mieux c'est
    • d'oublier tout les facilités des languages dont les types wchar std::string, std::wstring ... même les conversions du compilateur L"" parce que soit tu ne connais pas vraiment l'encodage/ comment tout cela travaille, soit c'est dépendant du système d'exploitation.
    • de travailler en hexadécimal (et donc unsigned char) avec les conversions qui vont bien
    • (*) d'avoir 1 moteur de chaînes de caractères avec 1 encodage précis (recherche, stockage, gestion multi-langues, ...) et 1) de faire les conversions nécessaires pour toutes les parties internes du programme (base de données, IHM (saisies, texte par exemple), ...) et 2) de maîtriser/ filter les resources externes (fichiers, réseau, ...)
    • la partie bibliothèque standard C qui manipule les chaînes de caractères peut être utilisée pour 2-3 opérations basiques.



    Citation Envoyé par kaitlyn Voir le message
    C'est un sujet plutôt complexe pour un débutant ! De plus, je remarque que la plupart des facilités de C++11 sont dépréciées, et ce qui reste dépend beaucoup des locales, de l'OS. La seule solution portable que je vois, hors bibliothèques tierces, c'est de travailler avec des char32_t, lire les fichiers de manière brut, convertir à la volée les séquences utf8/lat9 en utf32 ( càd en code point à stocker dans un char32_t), puis chercher leurs présences à coup de string.find().
    Ce n'est pas terrible comme solution parce que tu maîtrises le programme et tous ces mécaniques internes ... donc trop de conversions.
    Le seul problème, ce sont les resources externes (fichiers, réseau, ...) et là cela peut être impossible si tu ne connais pas l'encodage de la source mais tu peux filter facilement

    Regarde mon troisième point (*)

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

Discussions similaires

  1. Compteur de voyelles
    Par bardiiar dans le forum C
    Réponses: 22
    Dernier message: 18/06/2019, 15h21
  2. Compteur de chaque voyelles dans une chaine de caractères
    Par jasma dans le forum Débuter avec Java
    Réponses: 4
    Dernier message: 11/10/2012, 10h38
  3. Filtrer les voyelles
    Par Babyneedle dans le forum Langage SQL
    Réponses: 9
    Dernier message: 22/12/2003, 15h12
  4. Remise à 0 d'un compteur automatique
    Par missllyss dans le forum SQL
    Réponses: 4
    Dernier message: 15/12/2003, 16h46
  5. Migration Access > SQL Server (suite) : Compteur
    Par LadyArwen dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 06/03/2003, 14h08

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