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 :

Recherche/remplacement de texte


Sujet :

C++

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2016
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2016
    Messages : 2
    Points : 7
    Points
    7
    Par défaut Recherche/remplacement de texte
    Bonjour,

    Je suis débutant en C++ et je suis entrain d'ébaucher un programme qui se comporte de la manière suivante :

    -D'un côté, il y a des fichiers textes qui contiennent des listes de mots : fichiers de vocabulaire.

    -De l'autre côté, il y a des fichiers qui contiennent des textes : fichiers que l'on va comparer avec les fichiers de vocabulaires.


    J'ai plusieurs fonctions,

    1: une qui permet de transformer les fichiers textes en vector <string>,

    cette dernière fait appel à une autre qui s'occupe de mettre ce texte en minuscule :

    a -La fonction textToList:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     vector<string> textToList(ifstream& txt, string ligne){
     
                    vector<string> vliste;
     
     
                    while(! txt.eof()){
                        txt >> ligne;
                        toLower(ligne);
                        vliste.push_back(ligne);
                    }
     
             return vliste;
       }
    b-La fonction ToLower:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void toLower(basic_string<char>& s) {
     
                    for (basic_string<char>::iterator p = s.begin(); p != s.end(); ++p) {
     
                        *p = tolower(*p);
                    }
     
               }

    2: Et enfin, une dernière qui, elle,

    me permet de rechercher dans le texte les mots de vocabulaire,

    et,

    si ces derniers sont présents, de les remplacer par le nom du fichier (dans lequel a été trouvé le mot de vocabulaire).

    a- La fonction searcher:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    vector<string> searcher(vector<string> voc, vector<string> txt, string name){
     
                    for(int i = 0; i < txt.size(); i++){
     
                            for(int j=0; j < voc.size(); j++){
                                    if(voc[j] == txt[i]){
                                        txt[i] = name;
                                    }
                            }
                        }
     
                    return txt;
                }
    dans laquelle: voc est la liste de vocabulaire, txt est le texte, name est le nom du fichier duquel provient la liste de vocabulaire.



    Je rencontre un résultat inattendu et cela à cause d'une erreur que je ne comprends pas:


    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
     
    int main()
    {
     
        vector <string> filenames;
        string ligne;
        vector<string> tableau;
     
        vector<string> finale;
     
        ifstream liste("liste.txt");
     
        ifstream txtFile("texts.txt");
        vector<string> texte;
     
        if(liste){
     
                // Text to list transforme le fichier liste en vecteur
     
            filenames = textToList(liste, ligne);
            texte = textToList(txtFile, ligne);
     
                    // Premier test:
                cout << "Premier test :" << endl;
     
                    // Ecrit les noms des fichiers
                for(int k = 0; k < filenames.size() - 1; k++){
     
                    cout << filenames[k] << endl;
                }
     
                    //Deuxième test
                cout << endl << endl << "deuxieme test :" << endl << endl;
     
     
                    //ouvre les fichiers de vocabulaire de la liste un à un
                for(int i = 0; i < filenames.size()-1; i++){
     
                        ifstream file(filenames[i].c_str());
     
                        cout << "Nom du fichier : " << filenames[i] << endl << endl;
     
     
                            //Text to list, transforme chaque fichier de vocabulaire en un même vecteur
                        tableau = textToList(file, ligne);
                        cout << "Mot original : " << tableau[i] << endl;
     
     
                        finale = searcher(tableau, texte, filenames[i]);
                        cout << "Mot Final : " << finale[i] << endl;
     
                        cout << "Nom du fichier maintenant : " << filenames[i] << endl;
                        tableau.clear();
     
     
     
     
     
     
                }
     
     
        }
     
        else{
     
            cout << "ERROR:2" << endl;
        }
     
     
     
                    for(int j = 0; j < finale.size()-1; j++){
     
                                cout << finale[j] << endl;
                        }
     
     
        return 0;
    }
    Comme on le voit, "filenames" reçoit les noms de fichier (stockés dans un fichier "liste.txt")

    ces noms de fichiers sont ensuite utilisés par le flux "file" dans une boucle for:

    ifstream file(filenames[i].c_str());



    "Tableau" reçoit le vocabulaire contenu dans ce fichier, il est une liste de vocabulaire, qui est censée se remplir

    puis se vider à chaque nouveau fichier ouvert par "file".



    Ensuite, le texte dans lequel on chercher ses mots est stocké dans "texte", et le résultat dirigé vers "finale".

    Donc, le résultat de "finale" devrait être le texte initial qui, lorsqu'il comporte un mot de ces fichiers de vocabulaire,

    est remplacé par l'expression contenue dans filenames[i].


    Mais cela ne fonctionne pas :



    Dans le fichier liste.txt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    com.txt test.txt tt.txt
    Dans le fichier com.txt:
    test.txt:
    tt.txt:



    Dans le fichier texts.txt (le texte dans lequel on recherche):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    bonjour salut alors comment ça va bonjour salut hello comment ça va mon gars bonjour mon vieux bonjour les fraises patates douces c'est cool


    (quand-il s'agit de choisir des exemples pour faire des tests, je ne connais pas vraiment de carences en inspiration.)



    Et, je reçois ce résultat :


    Nom : test2.png
Affichages : 115
Taille : 1,5 Ko

    Le système que j'emploie ne semble prendre compte que d'un seul fichier.



    (je m'excuse de ce post un peu long)



    Sauriez-vous, avec votre regard neuf et savant, m'éclairer sur ce problème ?

    Je vous remercie de votre patience, et j'espère que ce n'est pas trop confus.

    Merci beaucoup.

  2. #2
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Bonjour,

    Dans ton code, tu as écrit :
    Citation Envoyé par JimFinn Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //ouvre les fichiers de vocabulaire de la liste un à un
    for(int i = 0; i < filenames.size()-1; i++){
    Tu as trois fichiers, mais ton indice i va seulement de 0 à 1. Il faut que tu enlèves ton -1.

    Dans cette boucle, on peut lire :
    Citation Envoyé par JimFinn Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    //Text to list, transforme chaque fichier de vocabulaire en un même vecteur
    tableau = textToList(file, ligne);
    cout << "Mot original : " << tableau[i] << endl;
    Après avoir récupéré le contenu de ton fichier numéro i, tu affiches le mot numéro i de ce fichier.
    Cela implique que, si un de tes fichiers a i mots ou moins, ton indice dépasse l'indice maximal du tableau et le comportement est indéterminé.

    Enfin, pour en venir à la cause de ton problème, toujours dans la même boucle, on lit :
    Citation Envoyé par JimFinn Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    finale = searcher(tableau, texte, filenames[i]);
    Donc seule la dernière itération de ta boucle déterminera le contenu de ta variable finale.
    D'ailleurs, dans ton message, n'aurais-tu pas inversé "test.txt" et "tt.txt" quelque part ?
    Selon mon analyse de ton code actuel, le seul fichier pris en compte est l'avant-dernier de la liste de "liste.txt".

    A part ça, il y a aussi des problèmes d'optimisation. Mais je n'ai pas encore le temps d'en parler.

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2016
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2016
    Messages : 2
    Points : 7
    Points
    7
    Par défaut
    Merci de ta réponse, tout d'abord,

    finalement j'ai trouvé une solution,
    c'est donc finalement une fonction,

    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
     
    vector<string> syntaxMaker(vector<string> filenames,string ligne, vector<string> texte){
     
        vector<string> voc;
        vector<string> finale;
       for(int i = 0; i < filenames.size()-1; i++){
                ifstream file(filenames[i].c_str());  //on charge le texte
                if(file){
                voc = textToList(file, ligne); // le texte est transformé en vector
                finale = searcher(voc, texte, filenames[i]); // on cherche dans le texte les expressions du vector et on les remplace par le nom du fichier
                texte = finale; //le texte devient le résultat de finale (peut être pourrait on faire  texte= searcher(voc,texte,filename[i], sur la ligne du dessus pour améliorer)
                voc.clear(); // la liste se vide (je ne sais pas si c'est obligatoire, pareil, j'essayerais
                }
                else{
                    cout << "error: list file doesn't exist!" << endl;
                }
     
            }
        return finale;
    }
    le problème venait du fait que le texte (deuxième paramètre de la fonction searcher) se réinitialisait,
    or, ma volonté était d'additionner les "couches" et non simplement de les remplacer.

    Nom : test3.png
Affichages : 111
Taille : 2,1 Ko

  4. #4
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Pour l'optimisation, je commenterai juste deux fonctions.

    Citation Envoyé par JimFinn Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     vector<string> textToList(ifstream& txt, string ligne){
     
                    vector<string> vliste;
     
     
                    while(! txt.eof()){
                        txt >> ligne;
                        toLower(ligne);
                        vliste.push_back(ligne);
                    }
     
             return vliste;
       }
    Dans cette fonction, tu passes un objet string ligne par valeur.
    Cela implique que ta variable ligne sera une copie de ce que tu auras passé en paramètre (sauf si tu passes en paramètre un objet temporaire, mais ce n'est pas le cas dans ton code qui appelle cette fonction).
    Ce coût est inutile car, de toutes façons, dans ta fonction, tu appelles operator>> pour écraser le contenu initial de la variable ligne.
    Il serait plus logique de définir ligne comme une variable locale à ta fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    std::vector<std::string> textToList(std::ifstream& txt){
        std::vector<std::string> vliste;
        std::string ligne;
        while(! txt.eof()){
            txt >> ligne;
            toLower(ligne);
            vliste.push_back(ligne);
        }
        return vliste;
    }
    Citation Envoyé par JimFinn Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    vector<string> searcher(vector<string> voc, vector<string> txt, string name){
     
                    for(int i = 0; i < txt.size(); i++){
     
                            for(int j=0; j < voc.size(); j++){
                                    if(voc[j] == txt[i]){
                                        txt[i] = name;
                                    }
                            }
                        }
     
                    return txt;
                }
    Dans cette fonction, tu passes tous tes objets par valeur, donc tu dupliques toutes les données, sauf dans certains cas particuliers où il peut y avoir une optimisation (si un paramètre est un objet temporaire ou si l'implémentation de string utilise le Copy On Write). C'est coûteux.

    • Dans le cas du paramètre voc, il s'agit d'un objet a priori volumineux que tu ne fais que lire. Il est donc préférable de faire un passage par référence constante pour éviter de dupliquer les données.
    • De plus, conceptuellement, voc est un ensemble de string dont l'ordre n'a pas d'importance. Si voc est un vector<string>, alors la recherche d'un élément a une complexité linéaire. Il vaut mieux que ce soit un unordered_set<string> qui, en interne, utilise une table de hachage. Alors, la recherche d'un élément a une complexité constante.
    • Concernant le paramètre txt, tu le dupliques puis tu modifies sa copie et tu retournes cette copie modifiée. Il serait plus optimisé de passer txt par référence non constante puis de le modifier dans la fonction. Cela permettra de modifier un même texte (sous forme de vector<string>) en appelant plusieurs fois ta fonction searcher sans avoir à créer de nouvel objet de type vector<string>.
    • Concernant le paramètre name, il vaut mieux faire un passage par référence constante pour éviter de dupliquer les données.


    La fonction ressemble alors à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void remplacerDansTexte(std::vector<std::string>&              texte,
                            const std::unordered_set<std::string>& motsARemplacer,
                            const std::string&                     motDeRemplacement)
    {
        for(size_t i = 0; i < texte.size(); ++i) {
            std::unordered_set<std::string>::const_iterator it = motsARemplacer.find(texte[i]);
            if(it != motsARemplacer.end())
                texte[i] = motDeRemplacement;
        }
    }

  5. #5
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    (Je n'ai pas lu la discussion.)

    Citation Envoyé par Pyramidev Voir le message
    std::unordered_set<std::string>::const_iterator it = motsARemplacer.find(texte[i]);
    if(it != motsARemplacer.end())
    texte[i] = motDeRemplacement;[/CODE]
    auto est assez commode ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    auto const it = motsARemplacer.find(texte[i]); // motsARemplacer est pris par const &, donc auto est bien un const_iterator
    Même si je préfère :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if (motsARemplacer.find(texte[i]) != motsARemplacer.end())
    {
        texte[i] = motDeRemplacement;
    }

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

Discussions similaires

  1. Rechercher / Remplacer du texte sur un champ
    Par jiojio dans le forum Langage SQL
    Réponses: 2
    Dernier message: 16/01/2015, 15h00
  2. [WD-2000] Rechercher-remplacer dans une zone de texte
    Par tegestobis dans le forum VBA Word
    Réponses: 4
    Dernier message: 04/09/2009, 14h35
  3. Rechercher/Remplacer un mot dans un texte
    Par epauusa dans le forum Pascal
    Réponses: 1
    Dernier message: 21/05/2009, 17h46
  4. Réponses: 8
    Dernier message: 12/11/2007, 10h16
  5. Réponses: 4
    Dernier message: 12/10/2006, 17h03

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