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

SL & STL C++ Discussion :

[débutant] equivalent à sprintf pour les std::string


Sujet :

SL & STL C++

  1. #1
    Membre actif Avatar de Biosox
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    298
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2005
    Messages : 298
    Points : 203
    Points
    203
    Par défaut [débutant] equivalent à sprintf pour les std::string
    Bonjour,

    je connais un peu C et je me met au C++. Le problème, c'est que je garde des reflexes C, comme utiliser des char* au lieu de std::string.

    maintenant j'essaye d'utiliser les strings, mais je bute sur un problème: je ne trouve pas de manière simple de générer des noms de fichiers qui contiennent un numero:

    en C je faisait ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    char filename[10];
    sprintf(filename,"file%3d.txt",counter);
    existe-it un équivalent (en une seule ligne) avec des std::string ?

    parce que faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    std::string filename
    std::ostringstream oss;
    filename = "file";
    oss << counter;
    filename += oss.str();
    filename += ".txt";
    je trouve ça un peu long!

    merci

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    [EDIT] Attention, dans ce post je propose une méthode qui est une mauvaise idée, lire la suite du thread. J'le f'rai p'u
    ----------------------------

    A part la méthode que tu cites, je n'en connais pas pour faire rapidement ce que tu veux (ce qui ne veut pas dire qu'il n'y en a pas !).
    Cela dit, tu peux t'en sortir en surchargeant l'operator+ global :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    std::string operator+(std::string inString, int inValue)
    {
          <le code à base de stringstream>
    }
    Ainsi que le même opérateur en symétrisant les arguments. Comme ça tu pourras écrire des trucs comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    std::string str = "ma chaine";
    int valeur = 2;
    std::string concatenation = str + valeur;
    Tu peux aussi te faire une classe dérivant de std::string à laquelle tu rajoutes les méthodes qui te manquent.

    C'est ce que j'ai fait quand j'ai eu les mêmes besoins que toi, je ne dis pas que c'est ce qu'il y a de mieux mais ça reste assez propre et efficace. Cela dit, je trouve ça louche que rien ne figure dans la STL pour faire ça plus simplement ...

  3. #3
    Membre actif Avatar de Biosox
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    298
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2005
    Messages : 298
    Points : 203
    Points
    203
    Par défaut
    merci, je pense que je vais surcharger l'operateur + comme tu le proposes, mais ce n'est malheureusement pas une solution parfaite, car elle convient uniquement au cas où on veut rajouter un entier à la fin de la chaîne, mais si il y en a plusieurs a des endroits différents (je pense à une arborescence de dossiers) ça n'aide pas tellement.

    merci quand même pour ton aide.

  4. #4
    Membre averti
    Avatar de bigquick
    Profil pro
    Inscrit en
    Août 2002
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 356
    Points : 353
    Points
    353
    Par défaut
    Salut,

    Je n'ai pas eu le temps de tester, mais je pense qu'en surchargeant l'operateur comme le propose dabeuliou, tu pourras écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for (int i=0; i<10; ++i)
    {
        std::string fichier = "fichier" + i + ".txt";
        faire_qqchose_avec(fichier);
    }
    Non ? Car fichier + i va retourner un string (appel de l'operateur), et après on se retrouve donc avec string+string, ce qui est défini...

    Reste à tester
    And still we will be here, standing like statues ...

  5. #5
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Pour du formattage à la printf mais en mieux, tu as boost::format.

    Sinon tu peux aussi faire des choses de ce genre, avec une simple fonction de conversion style celle de la FAQ :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    string filename = "file" + ToString(i) + ".txt";
    Ca évite d'avoir à écrire des surcharges d'opérateurs qui peuvent être dangereuses.

    Si tu souhaites ajouter du formatage plus évolué il faudra passer par les stringstreams, mais en général lorsqu'on a besoin d'un tel formattage on se soucie peu de le faire plutôt en 2 ou en 3 lignes. D'autant que tu en rajoutais inutilement dans ton code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::ostringstream oss;
    oss << "file" << counter << ".txt";
    std::string filename = oss.str();

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    bigquick -> Je ne sais pas si ce que tu as écrit marchera, je ne me souviens plus de l'ordre de priorité entre l'opérateur= et l'opérateur+.
    Par contre, ça, ça marchera à coup sûr :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    std::string fichier = "fichier"
    fichier = fichier + i + ".txt";
    ou encore
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::string fichier = std::string("fichier") + i + ".txt";
    On a le droit d'assigner une constante de type const char* (comme "fichier") à une std::string car le compilo va utiliser le constructeur prenant un const char* comme paramètre pour initialiser la std::string.

  7. #7
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    bigquick -> Je ne sais pas si ce que tu as écrit marchera, je ne me souviens plus de l'ordre de priorité entre l'opérateur= et l'opérateur+.
    Si l'affectation était prioritaire sur l'addition ce serait assez grave

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int i;
    i = 4 + 5;
     
    // donnerait :
     
    int i;
    (i = 4) + 5; // ce qui met 4 dans i et renvoie 9 dans le vide...

  8. #8
    Membre averti
    Avatar de bigquick
    Profil pro
    Inscrit en
    Août 2002
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 356
    Points : 353
    Points
    353
    Par défaut
    Ah oui, c'est vrai que il faut peut etre préciser std::string(fichier) si on veut être sur que le compilateur ne le prenne pas por un const char*.

    Mais c'est vraique de toute façon:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::ostringstream oss;
    oss << "file" << counter << ".txt";
    std::string filename = oss.str();
    C'est largement raisonnable niveau longueur à écrire

    (edit: en effet, une affectation prioritaire serait légèrement problématique )
    And still we will be here, standing like statues ...

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    Oui bon, ça va, ça va ...

    Si il faut réfléchir avant de poster, où va ?

    Maintenant, je ne suis pas du tout d'accord avec vous quand vous acceptez de répeter n fois les 3 lignes nécessaires pour concaténer une chaîne et un nombre. 3 lignes, c'est certes peu mais factoriser le code n'a jamais été mauvais ! Imaginez que vous découvrez un bug dans ces trois lignes, il faudrait repasser partout pour tout corriger, avec le risque d'en oublier.

    Bon, alors, un point partout ?

  10. #10
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Ben... Entre 2 lignes avec sprintf et 3 avec ostringstream, je ne vois pas trop ce qui te gêne.

    Et je ne comprend pas ce que tu veux factoriser, à moins que tous tes formatages de texte soient similaires. Si tu ne veux que concaténer des nombres et des chaînes, sans formatage, alors passe comme je te l'ai dit par une fonction ToString et l'opérateur + qui est défini pour std::string.

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    Ok, on ne parlait pas de la même chose : j'avais l'impression que bigquick acceptait de ne pas créer de méthode pour concaténer une chaîne et un nombre et de répéter les 3 lignes nécessaires partout où il voulait faire une telle concaténation.
    Sinon, je suis d'accord que pour l'implémentation de cette méthode, peu importe d'utiliser un stringstream, sprintf ou un lutin des bois.

    Par contre, pourquoi tu n'aimes pas ma méthode qui consiste à surcharger l'operator+ pour pouvoir concaténer directement une string et un nombre ? Tu la trouvais dangereuse, tu peux t'expliquer ? C'est dommage parce que ça allège considérablement les écritures (un peu plus que ToString()) et c'est pas négligeable.

  12. #12
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Par contre, pourquoi tu n'aimes pas ma méthode qui consiste à surcharger l'operator+ pour pouvoir concaténer directement une string et un nombre ? Tu la trouvais dangereuse, tu peux t'expliquer ? C'est dommage parce que ça allège considérablement les écritures (un peu plus que ToString()) et c'est pas négligeable.
    Ca pourrait créer des habitudes menant à des codes incorrects comme celui-ci par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::string s = "file" + 2;
     
    // s contient "le" et non "file2"
    C'est le premier qui me vient à l'idée, mais ce n'est sûrement pas le seul.

  13. #13
    Membre averti
    Avatar de bigquick
    Profil pro
    Inscrit en
    Août 2002
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 356
    Points : 353
    Points
    353
    Par défaut
    Euh ... bah une méthode pour concatener je ne sais pas trop .... il faut connaitre le nombre d'arguments que tu veux concatener, ou alors écrire un operateur par type à concaténer, mais c'est dangereux comme le dit Loulou24 ...

    D'ailleurs j'ai vraiment parlé trop vite tout à l'heure
    std::string fichier = "fichier" + i + ".txt";
    ca va faire completement n'importe quoi , il faut bien lui indiquer que le premier est un string pour que ca s'enchaine en cascade ...

    Enfin donc pour moi, si c'est pour formatter un grand nombre de chaines selon le même format, c'est mieux de créér une fonction avec les parametres qui vont bien, mais si c'est juste pour concatener quelques chaines par ci par la, ce n'est pas si grave, enfin pas plus qu'un sprintf ...

    Enfin le plus efficace ça doit bien être les toString() de la faq ... mais ca sert pas à concatener, juste à prémacher le travail de l'operateur + des strings
    And still we will be here, standing like statues ...

  14. #14
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Une solution peut-être un peu plus générique que les toString de la faq existe dans boost, et se nomme lexical_cast. Avec ça, le code devient :

    string fichier = "Fichier" + lexical_cast<string>(i) + ".txt";
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  15. #15
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

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

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Points : 17 323
    Points
    17 323
    Par défaut
    Citation Envoyé par JolyLoic
    Une solution peut-être un peu plus générique que les toString de la faq existe dans boost, et se nomme lexical_cast. Avec ça, le code devient :

    string fichier = "Fichier" + lexical_cast<string>(i) + ".txt";
    je rebondis sur le sujet
    et si j'ai envie que counter soit calé avec des zeros je fais comment ?
    exemple je reprend l'exemple de base et je modifie le format:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    char filename[20];
    counter=3;
    sprintf(filename,"file%03d.txt",counter);
    on obtient : "file003.txt" .

  16. #16
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Comme déjà dit, cette solution n'est valable que si on ne souhaite pas de formatage, dans le cas contraire on passera par un ostringstream directement.

  17. #17
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    La surcharge de op+ me fait craindre avec wchar_t qui n'est pas toujours un type natif "indépendant", mais parfois un simple short (ou int?).
    Bref, avec une telle surcharge, std::string et std::wstring auraient des sémantiques qui divergeraient légèrement.

    De plus, je veux pouvoir écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::string s;
    s += 'a';
    string t = s + 'b';
    Avec les int au milieu, je craindrais que le comportement change en deça de certaines plages, ou que du code soit cassé par de mauvais compilos, ...
    N'oubliez pas qu'un char est aussi un nombre.


    Pour les pinailleurs qui cherchent l'efficacité à tout prix lors des convertions, voir la série d'articles (de Matthew Wilson je crois) sur Efficient integer to string convertions dispo sur le site du C/C++ Users Journal (aka cuj).


    Si tu veux caler avec des zéros: std::ostringstream est très bien. Et probablement boost.format aussi.


    (tiens?! La version 1.33 de boost vient de sortir et ils ont changé la page de garde du site...)
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  18. #18
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 82
    Points : 68
    Points
    68
    Par défaut
    Citation Envoyé par Loulou24
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::string s = "file" + 2;
    // s contient "le" et non "file2"

    Aaaargh, oui ! Je n'avais jamais pensé à ce piège. Bon, alors je retire mon idée de surcharger l'operator+, c'était effectivement à la limite du terrorisme.

    Et je m'en vais corriger mon code, avant que ça n'explose ...

  19. #19
    Membre actif Avatar de Biosox
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    298
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2005
    Messages : 298
    Points : 203
    Points
    203
    Par défaut
    Merci pour vos réponses. je vais utiliser la methode du "ToString(i)". mais j'ai l'intention de modifier cette fonction afin de pouvoir générer des "003" plutot que des "3" (si je me fais bien comprendre)

    encore une question: qqun peut-il m'expliquer ceci:

    Citation Envoyé par Loulou24
    (...)des codes incorrects comme celui-ci par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    std::string s = "file" + 2;
     
    // s contient "le" et non "file2"
    je ne comprends pas pourquoi?

  20. #20
    Membre averti
    Avatar de bigquick
    Profil pro
    Inscrit en
    Août 2002
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 356
    Points : 353
    Points
    353
    Par défaut
    Ca arrive puisque "test" est un const char*, donc un pointeur sur des char (constants). C'est tout à fait autorisé d'additioner des pointeurs, ou des pointeurs et des entiers, ce qui a pour effet de déplacer le pointeur en mémoire. Un exemple plus simple et plus connu est:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
       char  chaine[] = "test";
       char* p = chaine;
     
       // on va parcourir la chaine jusqu'à tomber sur le "caractère" NULL (fin de chaine)
       while (*p != NULL)
       {
          cout << *p << endl;  // affiche le caractère courant
          ++p;                 // passe au suivant
          //  tu peux mettre  p = p + sizeof(char);  à la place de ++p;
       }
    Ce qui fait avancer ton pointeur de char en char jusqu'à la fin de la chaine, et affiche donc t \ e\ s \ t (un caractère par ligne).

    Donc dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::string s = "file" + 2;
    "file" retourne un pointeur sur le 1er caractère de la chaine, et donc "file" + 2 un pointeur sur le 3ème
    And still we will be here, standing like statues ...

Discussions similaires

  1. Manipuler les std::string
    Par camboui dans le forum SL & STL
    Réponses: 13
    Dernier message: 08/01/2009, 21h36
  2. sprintf avec des std::string
    Par Bart_lx dans le forum C++
    Réponses: 13
    Dernier message: 07/12/2007, 09h10
  3. Questions sur les std::string
    Par olive_le_malin dans le forum SL & STL
    Réponses: 6
    Dernier message: 23/02/2007, 08h44
  4. Pourquoi refuser les std::string
    Par dj.motte dans le forum SL & STL
    Réponses: 18
    Dernier message: 09/01/2007, 22h59
  5. Equivalent de (*) pour les champs date et num
    Par pursang25 dans le forum Access
    Réponses: 3
    Dernier message: 11/07/2006, 21h39

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