web-dev-qa-db-fra.com

Alternative à String.Format en C ++

Je n'ai pas beaucoup d'expérience avec C++. J'ai plutôt travaillé plus en C # et donc, je voulais poser ma question en rapport avec ce que j'aurais fait là-dedans. Je dois générer un format spécifique de la chaîne, que je dois transmettre à une autre fonction. En C #, j'aurais facilement généré la chaîne via le code simple ci-dessous.

string a = "test";
string b = "text.txt";
string c = "text1.txt";

String.Format("{0} {1} > {2}", a, b, c);

En générant une telle chaîne ci-dessus, je devrais pouvoir passer ceci dans system(). Cependant, system accepte uniquement char*

Je suis sur Win32 C++ (Pas C++/CLI), et je ne peux pas utiliser boost car cela inclurait trop d'inclusion de tous les fichiers pour un projet qui lui-même est très petit. Quelque chose comme sprintf() me semble utile, mais sprintf n'accepte pas string comme a, b et c paramètres. Des suggestions sur la façon dont je peux générer ces chaînes formatées pour les transmettre au système dans mon programme?

27
user1240679

Vous pouvez utiliser sprintf en combinaison avec std::string.c_str().

c_str() renvoie un const char* et fonctionne avec sprintf:

string a = "test";
string b = "text.txt";
string c = "text1.txt";
char* x = new char[a.length() + b.length() + c.length() + 32];

sprintf(x, "%s %s > %s", a.c_str(), b.c_str(), c.c_str() );

string str = x;
delete[] x;

ou vous pouvez utiliser un tableau char pré-alloué si vous connaissez la taille:

string a = "test";
string b = "text.txt";
string c = "text1.txt";
char x[256];

sprintf(x, "%s %s > %s", a.c_str(), b.c_str(), c.c_str() );
7
Luchian Grigore

La manière C++ serait d'utiliser un std::stringstream objet comme:

std::stringstream fmt;
fmt << a << " " << b << " > " << c;

La manière C serait d'utiliser sprintf.

La voie C est difficile à obtenir car:

  • Il est de type dangereux
  • Nécessite la gestion du tampon

Bien sûr, vous voudrez peut-être vous replier sur la voie C si les performances sont un problème (imaginez que vous créez des millions de petits objets stringstream de taille fixe, puis les jetez).

34
dirkgently

Par souci d'exhaustivité, vous pouvez utiliser std::stringstream :

#include <iostream>
#include <sstream>
#include <string>

int main() {
    std::string a = "a", b = "b", c = "c";
    // apply formatting
    std::stringstream s;
    s << a << " " << b << " > " << c;
    // assign to std::string
    std::string str = s.str();
    std::cout << str << "\n";
}

Ou (dans ce cas) std::string possède ses propres capacités de concaténation de chaînes:

#include <iostream>
#include <string>

int main() {
    std::string a = "a", b = "b", c = "c";
    std::string str = a + " " + b + " > " + c;
    std::cout << str << "\n";
}

Pour référence:


Si vous voulez vraiment aller dans le sens C. Vous voilà:

#include <iostream>
#include <string>
#include <vector>
#include <cstdio>

int main() {
    std::string a = "a", b = "b", c = "c";
    const char fmt[] = "%s %s > %s";
    // use std::vector for memory management (to avoid memory leaks)
    std::vector<char>::size_type size = 256;
    std::vector<char> buf;
    do {
        // use snprintf instead of sprintf (to avoid buffer overflows)
        // snprintf returns the required size (without terminating null)
        // if buffer is too small initially: loop should run at most twice
        buf.resize(size+1);
        size = std::snprintf(
                &buf[0], buf.size(),
                fmt, a.c_str(), b.c_str(), c.c_str());
    } while (size+1 > buf.size());
    // assign to std::string
    std::string str = &buf[0];
    std::cout << str << "\n";
}

Pour référence:


Ensuite, il y a Boost Format Library . Pour votre exemple:

#include <iostream>
#include <string>
#include <boost/format.hpp>

int main() {
    std::string a = "a", b = "b", c = "c";
    // apply format
    boost::format fmt = boost::format("%s %s > %s") % a % b % c; 
    // assign to std::string
    std::string str = fmt.str();
    std::cout << str << "\n";
}
20
moooeeeep

En plus des options suggérées par d'autres, je peux recommander la bibliothèque fmt qui implémente un formatage de chaîne similaire à str.format in Python et String.Format en C #. Voici un exemple:

std::string a = "test";
std::string b = "text.txt";
std::string c = "text1.txt";
std::string result = fmt::format("{0} {1} > {2}", a, b, c);

Avertissement: je suis l'auteur de cette bibliothèque.

13
vitaut

Vous pouvez simplement concaténer les chaînes et créer une ligne de commande.

std::string command = a + ' ' + b + " > " + c;
system(command.c_str());

Vous n'avez pas besoin de bibliothèques supplémentaires pour cela.

2
Bo Persson

Pour être complet, la manière la plus rapide serait d'utiliser boost::format

cout << boost::format("%s %s > %s") % a % b % c;

Faites votre choix. La solution boost a l'avantage de la sécurité de type avec le format sprintf (pour ceux qui trouvent le << syntaxe un peu maladroite).

2
Shep

Comme déjà mentionné, la méthode C++ utilise des flux de chaînes.

#include <sstream>

string a = "test";
string b = "text.txt";
string c = "text1.txt";

std::stringstream ostr;
ostr << a << " " << b << " > " << c;

Notez que vous pouvez obtenir la chaîne C à partir de l'objet de flux de chaîne comme ceci.

std::string formatted_string = ostr.str();
const char* c_str = formatted_string.c_str();
1
user1359278