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 :

Problème double backslash


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    22
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 22
    Points : 14
    Points
    14
    Par défaut Problème double backslash
    Bonjour,

    je souhaite à l'aide d'un programme simple remplacer une chaine de caractère par une autre, je souhaite remplacer par pour se faire, voici mon programme :

    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
    #include <iostream>
    #include <string>
    using namespace std;
     
    int main ()
    {
      string base="[coucou] [ca] [va]";
     
      string str=base;
     
      while ( str.find("[") < str.length() ) {
        str.replace(str.find("["),1,"\[");
      }  
     
      cout << str << endl;
     
      system("PAUSE");
      return 0;
    }

    Lorsque j'utilise cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    str.replace(str.find("["),1,"\[");
    le programme plante

    Lorsque j'utilise celle ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    str.replace(str.find("["),1,"\\[");
    jobtiens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[coucou] [ca] [va]
    Appuyez sur une touche pour continuer...
    quelqu'un connait-il la solution ?

  2. #2
    Invité
    Invité(e)
    Par défaut
    Ta recherche du caractère repart toujours du début de la chaine...

    A la première itération ta chaine vaut

    [coucou] [ca] [va]

    tu vas trouver le [ en position 1, et le remplacer par \[ (il faut en C++ un double backslash, le premier étant l'échappemen)

    du coup ta chaine vaut

    \[coucou] [ca] [va]

    et maintenant, le find suivant va trouver le premier [, c'est à dire le même que tout à l'heure... et tu vas avoir en retour la chaine...

    \\[coucou] [ca] [va]

    et ainsi de suite...

    Pour corriger ton programme, il faut utiliser la valeur de retour de find(), en faisant qq chose comme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int pos=0;
    while(pos<str.size()) {
      pos=str.find("[",pos);
      str.replace(pos,1,"\\[");
      pos+=2;
    }
    Francois

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    Je modifierais même plutot le code en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    size_t pos=str.find('[');
    while (pos!=std::string::npos) /* npos est une valeur statique de la classe
                                    * std::string qui correspond à un index invalide
                                    */
    {
        str.replace(pos,1,"\[");
        /* cherchons l'occurrence suivante */
        pos=str.find('[');
    }
    En effet, size est une fonction susceptible, en fonction de l'implémentation, de nécessiter un calcul avant de fournir un résultat.

    Il est, bien sur possible, sur certains compilateurs, de passer un argument indiquant qu'il faut garder les constantes, mais ce peut être dangereux dans un environnement multi threadé par exemple.

    Il est donc préférable d'utiliser les possibilités que nous avons à notre disposition d'obtenir un résultat en temps constant:
    • npos au lieu de size() pour savoir si une sous chaine a été trouvée
    • empty() au lieu de size()>0 pour savoir si la chaine est vide ou non

    Au passage, le conseil sur empty() est également valable pour tous les conteneurs de la STL

    [EDIT]Et sinon, il existe des bibliothèques permettant de manipuler des expressions régullières (boost regex entre autres)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Invité
    Invité(e)
    Par défaut
    Euh koala, si tu n'incrémentes pas pos entre le replace() et le find() suivant, tu vas être ramené au problème précédent... (c'est à dire, tu vas toujours retrouver le même '[', puisque chaque replace() en ajoute un à droite de pos...

    Francois

  5. #5
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Je suis donc le seul à penser qu'il faudrait faire comme ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    std::ostringstream ss;
    size_t strSize = str.size();
    for(size_t i = 0; i < strSize;++i)
    {
      if(str[i] == '[')
        ss << '\\';
      ss << str[i];
    }
    str = ss.str();
    (qu'on pourrait largement simplifier avec un std::for_each et une lambda)

  6. #6
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Je suis donc le seul à penser qu'il faudrait faire comme ça ?
    Perso, je préfèrerais replace : si tu veux modifier la chaine recherchée et la chaine remplacée (moyennant une petite adaptation : pos+=repl.size(); ) c'est très simple. Dans ta version, pour changer la chaine de remplacement de "\[" en "\ç", il va falloir aller bricoler dans la boucle...

    Une version plus complète, qui incorpore les remarques de koala sur npos, serait

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    string rech="[";
    string repl="\\[";
    int rchsz=rech.size();
    int rplsz=repl.size();
    int pos=  pos=str.find(rech);
    while(pos!=string::npos {
      str.replace(pos,rchsz,repl);
      pos+=rplsz;
      pos=str.find(rech,pos);
    }
    L'intérêt du truc, c'est qu'on peut passer un peu ce qu'on veut comme rech et repl.

    Un autre défaut de l'approche par les stringstream c'est qu'elle recopie toute la chaine. Si l'on travaille sur de longues chaines, et que le caractère à remplacer est rare, voire inexistent, la version replace ira très vite, la version stringstream va être plus lente...

    Francois
    Dernière modification par Invité ; 13/08/2009 à 10h35.

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Euh koala, si tu n'incrémentes pas pos entre le replace() et le find() suivant, tu vas être ramené au problème précédent... (c'est à dire, tu vas toujours retrouver le même '[', puisque chaque replace() en ajoute un à droite de pos...

    Francois
    Au temps pour moi...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    size_t pos=str.find('[');
    while (pos!=std::string::npos) /* npos est une valeur statique de la classe
                                    * std::string qui correspond à un index invalide
                                    */
    {
        str.replace(pos,1,"\[");
        /* cherchons l'occurrence suivante */
        pos=str.find('[',pos+2);
    }
    te conviendrait-il mieux

    Au fait, le but est-il de voir le back slach à l'affichage

    Si oui, il faut échapper le backslash et utiliser pos+3 lorsque l'on cherche l'occurrence suivante



    Citation Envoyé par white_tentacle Voir le message
    Je suis donc le seul à penser qu'il faudrait faire comme ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    std::ostringstream ss;
    size_t strSize = str.size();
    for(size_t i = 0; i < strSize;++i)
    {
      if(str[i] == '[')
        ss << '\\';
      ss << str[i];
    }
    str = ss.str();
    (qu'on pourrait largement simplifier avec un std::for_each et une lambda)
    Ton code ne marche pas mieux que les autres... Il part dans une boucle infinie
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    22
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 22
    Points : 14
    Points
    14
    Par défaut
    Merci beaucoup fcharton, ton code marche nickel !!

  9. #9
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Ton code ne marche pas mieux que les autres... Il part dans une boucle infinie
    Euh... Non . J'ai même un variant (strSize - i) qui me garantit la terminaison.

    J'ai l'impression que tu n'es pas bien réveillé ce matin, toi .

  10. #10
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Au fait, le but est-il de voir le back slach à l'affichage

    Si oui, il faut échapper le backslash et utiliser pos+3 lorsque l'on cherche l'occurrence suivante
    T'es sur? Il me semblait que l'échappement est traité à la compilation : "\\[", ca fait 2 caractères, toujours... et "\\" ca n'en fait qu'un. Ou c'est moi qui déraille?

    Citation Envoyé par koala01 Voir le message
    Ton code ne marche pas mieux que les autres... Il part dans une boucle infinie
    Non, parce que dans la version de white tentacle, str n'est pas modifié. Le compteur i avance d'une position à chaque étape, pas de boucle infinie possible.

    Francois

  11. #11
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Euh... Non . J'ai même un variant (strSize - i) qui me garantit la terminaison.

    J'ai l'impression que tu n'es pas bien réveillé ce matin, toi .
    Effectivement, je suis mal réveillé

    En faisant un copier coller, j'ai oublié d'effacer quelques lignes de mon dernier test (celui présentant ma version correcte ), et c'était... la boucle while
    Disons que j'ai quelques excuses, même si je ne veux pas les étaler ici


    Citation Envoyé par fcharton Voir le message
    T'es sur? Il me semblait que l'échappement est traité à la compilation : "\\[", ca fait 2 caractères, toujours... et "\\" ca n'en fait qu'un. Ou c'est moi qui déraille?
    Sur ce coup là, je suis catégorique

    Testé et tout et tout (et sans avoir fait de fautes d'attention, cette fois ), même si je n'ai pas d'autre raison à te donner que "le \ d'échappement est un caractère comme un autre devant prendre place dans la chaine"

    Il y a peut être une option de compilation permettant de faire autrement ceci dit
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  12. #12
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Un autre défaut de l'approche par les stringstream c'est qu'elle recopie toute la chaine. Si l'on travaille sur de longues chaines, et que le caractère à remplacer est rare, voire inexistent, la version replace ira très vite, la version stringstream va être plus lente...
    Ça me semblait une affirmation en l'air, alors, j'ai voulu la vérifier... Et, c'est vrai.

    Bon, les stream sont lents, donc j'ai aussi fait une version à base de copie, mais en utilisant une chaîne de caractère. On arrive, sur des petites chaînes, à des perfs meilleures si la chaîne à remplacer est fréquente, et ça s'effondre dès qu'on passe sur des chaînes plus grandes.

    La faute, je pense, à beaucoup trop de page fault plutôt qu'à la copie elle-même.

  13. #13
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Testé et tout et tout (et sans avoir fait de fautes d'attention, cette fois ), même si je n'ai pas d'autre raison à te donner que "le \ d'échappement est un caractère comme un autre devant prendre place dans la chaine"
    Euh, non, le caractère d'échappement est traité à la compilation, et n'existe plus dans la chaîne.

    Par contre, sizeof("\\") fait bien 2, mais à cause du zéro terminal...

    Ou alors, j'ai pas compris de quoi vous parliez.

  14. #14
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Une autre solution pour éviter les copies inutiles est de ne placer de le flux que... ce qui doit être converti
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    std::stringstream ss;
    ss<<variable;
    std::string final=pre+ss.string();
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

Discussions similaires

  1. Problème avec les double backslash
    Par vinystic dans le forum Paradox
    Réponses: 2
    Dernier message: 08/10/2012, 15h30
  2. [Websphere Portal] Problème double connexion sur la portlet de connexion
    Par blionel dans le forum Portails
    Réponses: 2
    Dernier message: 03/06/2007, 13h26
  3. problème double login
    Par taka10 dans le forum Langage
    Réponses: 4
    Dernier message: 28/03/2007, 11h39
  4. [C#] problème double click
    Par Gloups dans le forum Windows Forms
    Réponses: 4
    Dernier message: 08/09/2006, 07h31
  5. [MySQL] Problème double insertion dans BDD
    Par oceane751 dans le forum PHP & Base de données
    Réponses: 34
    Dernier message: 28/12/2005, 00h09

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