Comment concaténer une chaîne std :: et un int?

655

Je pensais que ce serait vraiment simple, mais cela présente des difficultés. Si j'ai

std::string name = "John";
int age = 21;

Comment les combiner pour obtenir une seule chaîne "John21"?

Obediah Stane
la source
Herb Sutter a un bon article sur ce sujet: "Les formateurs de cordes de Manor Farm" . Il couvre Boost::lexical_cast, std::stringstream, std::strstream(qui est dépréciée), et sprintfcontre snprintf.
Fred Larson
Permettez-moi d'ajouter à ceci: j'ai essayé 'str = "hi"; str + = 5; cout << str; ' et n'a vu aucun effet. Il s'avère que cela appelle l'opérateur + = (char) et ajoute un caractère non imprimable.
daveagp du

Réponses:

1126

Par ordre alphabétique:

std::string name = "John";
int age = 21;
std::string result;

// 1. with Boost
result = name + boost::lexical_cast<std::string>(age);

// 2. with C++11
result = name + std::to_string(age);

// 3. with FastFormat.Format
fastformat::fmt(result, "{0}{1}", name, age);

// 4. with FastFormat.Write
fastformat::write(result, name, age);

// 5. with the {fmt} library
result = fmt::format("{}{}", name, age);

// 6. with IOStreams
std::stringstream sstm;
sstm << name << age;
result = sstm.str();

// 7. with itoa
char numstr[21]; // enough to hold all numbers up to 64-bits
result = name + itoa(age, numstr, 10);

// 8. with sprintf
char numstr[21]; // enough to hold all numbers up to 64-bits
sprintf(numstr, "%d", age);
result = name + numstr;

// 9. with STLSoft's integer_to_string
char numstr[21]; // enough to hold all numbers up to 64-bits
result = name + stlsoft::integer_to_string(numstr, 21, age);

// 10. with STLSoft's winstl::int_to_string()
result = name + winstl::int_to_string(age);

// 11. With Poco NumberFormatter
result = name + Poco::NumberFormatter().format(age);
  1. est sûr, mais lent; nécessite Boost (en-tête uniquement); la plupart / toutes les plateformes
  2. est sûr, nécessite C ++ 11 ( to_string () est déjà inclus dans #include <string>)
  3. est sûr et rapide; requiert FastFormat , qui doit être compilé; la plupart / toutes les plateformes
  4. ( idem )
  5. est sûr et rapide; nécessite la bibliothèque {fmt} , qui peut être compilée ou utilisée dans un mode en-tête uniquement; la plupart / toutes les plateformes
  6. sûr, lent et verbeux; nécessite #include <sstream>(du standard C ++)
  7. est fragile (vous devez fournir un tampon suffisamment grand), rapide et verbeux; itoa () est une extension non standard et n'est pas garantie d'être disponible pour toutes les plateformes
  8. est fragile (vous devez fournir un tampon suffisamment grand), rapide et verbeux; ne nécessite rien (est standard C ++); toutes les plateformes
  9. est fragile (vous devez fournir un tampon suffisamment grand), probablement la conversion la plus rapide possible , verbeuse; nécessite STLSoft (en-tête uniquement); la plupart / toutes les plateformes
  10. safe-ish (vous n'utilisez pas plus d'un appel int_to_string () dans une seule instruction), fast; nécessite STLSoft (en-tête uniquement); Windows seulement
  11. est sûr, mais lent; nécessite Poco C ++ ; la plupart / toutes les plateformes
DannyT
la source
13
Mis à part le lien que vous avez fourni, sur quoi basez-vous vos commentaires sur les performances?
JamieH
2
C'est presque toute votre réputation à partir d'une seule réponse !! Vous êtes chanceux;) Je pense que 8 est du C standard (bien sûr aussi du C ++), mais vaut probablement la peine d'être différencié.
noelicus
2. est lent car std :: to_string (age) crée une chaîne temporaire qui est ajoutée au résultat.
Igor Bukanov
Si vous êtes sur Arduino, vous pouvez également utiliser String(number).
Machado
267

En C ++ 11, vous pouvez utiliser std::to_string, par exemple:

auto result = name + std::to_string( age );
Jeremy
la source
j'aime celui-ci, simple. Merci.
truthadjustr
85

Si vous avez Boost, vous pouvez convertir l'entier en chaîne à l'aide de boost::lexical_cast<std::string>(age).

Une autre façon est d'utiliser des chaînes de caractères:

std::stringstream ss;
ss << age;
std::cout << name << ss.str() << std::endl;

Une troisième approche consisterait à utiliser sprintfou à snprintfpartir de la bibliothèque C.

char buffer[128];
snprintf(buffer, sizeof(buffer), "%s%d", name.c_str(), age);
std::cout << buffer << std::endl;

D'autres affiches ont suggéré d'utiliser itoa. Ce n'est PAS une fonction standard, donc votre code ne sera pas portable si vous l'utilisez. Il existe des compilateurs qui ne le prennent pas en charge.

Jay Conrod
la source
Notez que snprintf n'est pas garanti pour terminer la chaîne par null. Voici une façon de vous assurer que cela fonctionne: <pre> buffer buffer [128]; buffer [sizeof (buffer) -1] = '\ 0'; snprintf (buffer, sizeof (buffer) -1, "% s% d", name.c_str (), age); std :: cout << buffer << std :: endl; </pre>
M. Fooz
Ma tendance serait de ne jamais utiliser sprintf, car cela peut entraîner des débordements de tampon. L'exemple ci-dessus est un bon exemple où l'utilisation de sprintf serait dangereuse si le nom était très long.
terson
notez que snprintf est également c ++ non standard (comme itoa que vous mentionnez). il est tiré de c99
Johannes Schaub - litb
@terson: Je ne vois aucune occurrence de sprintfdans la réponse, seulement snprintf.
David Foerster
80
#include <iostream>
#include <sstream>

std::ostringstream o;
o << name << age;
std::cout << o.str();
Ben Hoffstein
la source
2
c'est super, le fichier d'en-tête BYT est sstream
landerlyoung
52
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
string itos(int i) // convert int to string
{
    stringstream s;
    s << i;
    return s.str();
}

Sans vergogne volé à http://www.research.att.com/~bs/bs_faq2.html .

tloach
la source
mais s est une variable de pile, la mémoire de ssera libre après appel itos. sdevrait allouer à partir du tas, et freeaprès utilisation, non?
kgbook
1
le retour par valeur est correct même si l'objet chaîne est hors de portée, stackoverflow.com/a/3977119/5393174
kgbook
32

C'est le moyen le plus simple:

string s = name + std::to_string(age);
Kevin
la source
8
Il s'agit d'une solution post-C ++ 11!
YamHon.CHAN
23

Si vous avez C ++ 11, vous pouvez utiliser std::to_string.

Exemple:

std::string name = "John";
int age = 21;

name += std::to_string(age);

std::cout << name;

Production:

John21
0x499602D2
la source
2
Ce serait name += std::to_string(static_cast<long long>(age));dans VC ++ 2010 comme vous pouvez le voir ici
néonate
@neonmate Et à la name += std::to_string(age + 0LL);place?
chux
18

Il me semble que la réponse la plus simple est d'utiliser la sprintffonction:

sprintf(outString,"%s%d",name,age);
user12576
la source
1
snprintf peut être délicat (principalement parce qu'il peut potentiellement ne pas inclure le caractère nul dans certaines situations), mais je préfère cela pour éviter les débordements potentiels du tampon sprintf.
terson
3
sprintf (char *, const char *, ...) échouera sur certaines versions des compilateurs lorsque vous passerez une chaîne std :: à% s. Pas tous, cependant (c'est un comportement indéfini) et cela peut dépendre de la longueur de chaîne (SSO). Veuillez utiliser .c_str ()
MSalters
plus sprintf est sujet à des débordements de buffer donc possible injection de code
Jean-François Fabre
15
#include <string>
#include <sstream>
using namespace std;
string concatenate(std::string const& name, int i)
{
    stringstream s;
    s << name << i;
    return s.str();
}
Seb Rose
la source
11
#include <sstream>

template <class T>
inline std::string to_string (const T& t)
{
   std::stringstream ss;
   ss << t;
   return ss.str();
}

Votre utilisation ressemblerait alors à ceci

   std::string szName = "John";
   int numAge = 23;
   szName += to_string<int>(numAge);
   cout << szName << endl;

Googlé [et testé: p]

Zing-
la source
10

Ce problème peut se faire de plusieurs manières. Je vais le montrer de deux manières:

  1. Convertissez le nombre en chaîne à l'aide de to_string(i).

  2. Utilisation de flux de chaînes.

    Code:

    #include <string>
    #include <sstream>
    #include <bits/stdc++.h>
    #include <iostream>
    using namespace std;
    
    int main() {
        string name = "John";
        int age = 21;
    
        string answer1 = "";
        // Method 1). string s1 = to_string(age).
    
        string s1=to_string(age); // Know the integer get converted into string
        // where as we know that concatenation can easily be done using '+' in C++
    
        answer1 = name + s1;
    
        cout << answer1 << endl;
    
        // Method 2). Using string streams
    
        ostringstream s2;
    
        s2 << age;
    
        string s3 = s2.str(); // The str() function will convert a number into a string
    
        string answer2 = "";  // For concatenation of strings.
    
        answer2 = name + s3;
    
        cout << answer2 << endl;
    
        return 0;
    }
lohith99
la source
Lequel est le plus rapide?
GyuHyeon Choi
7

Si vous souhaitez utiliser +pour la concaténation de tout ce qui a un opérateur de sortie, vous pouvez fournir une version modèle de operator+:

template <typename L, typename R> std::string operator+(L left, R right) {
  std::ostringstream os;
  os << left << right;
  return os.str();
}

Ensuite, vous pouvez écrire vos concaténations de manière simple:

std::string foo("the answer is ");
int i = 42;
std::string bar(foo + i);    
std::cout << bar << std::endl;

Production:

the answer is 42

Ce n'est pas le moyen le plus efficace, mais vous n'avez pas besoin du moyen le plus efficace, sauf si vous faites beaucoup de concaténation dans une boucle.

uckelman
la source
Si j'essaye d'ajouter des entiers ou un entier et un double, cette fonction sera-t-elle appelée? Je me demande si cette solution remplacera les ajouts habituels ...
Hilder Vitor Lima Pereira
L'opérateur renvoie un std::string, donc ne serait pas candidat dans les expressions où une chaîne n'est pas convertible en le type requis. Par exemple, ce operator+n'est pas éligible pour être utilisé +dans int x = 5 + 7;. Tout bien considéré, je ne définirais pas un opérateur comme celui-ci sans une raison très convaincante, mais mon objectif était de proposer une réponse différente des autres.
uckelman
Vous avez raison (je viens de le tester ...). Et quand j'ai essayé de faire quelque chose comme la chaîne s = 5 + 7 , j'ai eu la conversion invalide d' erreur de 'int' en 'const char ' *
Hilder Vitor Lima Pereira
5

Si vous utilisez MFC, vous pouvez utiliser un CString

CString nameAge = "";
nameAge.Format("%s%d", "John", 21);

Managed C ++ possède également un formateur de chaînes .

bsruth
la source
4

Le std :: ostringstream est une bonne méthode, mais parfois cette astuce supplémentaire peut être utile pour transformer le formatage en une ligne:

#include <sstream>
#define MAKE_STRING(tokens) /****************/ \
    static_cast<std::ostringstream&>(          \
        std::ostringstream().flush() << tokens \
    ).str()                                    \
    /**/

Vous pouvez maintenant formater des chaînes comme ceci:

int main() {
    int i = 123;
    std::string message = MAKE_STRING("i = " << i);
    std::cout << message << std::endl; // prints: "i = 123"
}
Pyry Jahkola
la source
4

Comme une question liée à Qt a été fermée en faveur de celle-ci, voici comment le faire en utilisant Qt:

QString string = QString("Some string %1 with an int somewhere").arg(someIntVariable);
string.append(someOtherIntVariable);

La variable chaîne a maintenant la valeur de someIntVariable à la place de% 1 et la valeur de someOtherIntVariable à la fin.

leinir
la source
QString ("Something") + QString :: number (someIntVariable) fonctionne également
gremwell
3

Il existe d'autres options possibles pour concaténer un entier (ou un autre objet numérique) avec une chaîne. C'est Boost.Format

#include <boost/format.hpp>
#include <string>
int main()
{
    using boost::format;

    int age = 22;
    std::string str_age = str(format("age is %1%") % age);
}

et Karma de Boost.Spirit (v2)

#include <boost/spirit/include/karma.hpp>
#include <iterator>
#include <string>
int main()
{
    using namespace boost::spirit;

    int age = 22;
    std::string str_age("age is ");
    std::back_insert_iterator<std::string> sink(str_age);
    karma::generate(sink, int_, age);

    return 0;
}

Boost.Spirit Karma prétend être l'une des options les plus rapides pour la conversion d' entiers en chaînes .

mloskot
la source
3

Vous pouvez concaténer int en chaîne en utilisant l'astuce simple donnée ci-dessous, mais notez que cela ne fonctionne que lorsque l'entier est à un seul chiffre. Sinon, ajoutez un nombre entier chiffre par chiffre à cette chaîne.

string name = "John";
int age = 5;
char temp = 5 + '0';
name = name + temp;
cout << name << endl;

Output:  John5
Sukhbir
la source
2

Voici une implémentation de la façon d'ajouter un int à une chaîne à l'aide des facettes d'analyse et de formatage de la bibliothèque IOStreams.

#include <iostream>
#include <locale>
#include <string>

template <class Facet>
struct erasable_facet : Facet
{
    erasable_facet() : Facet(1) { }
    ~erasable_facet() { }
};

void append_int(std::string& s, int n)
{
    erasable_facet<std::num_put<char,
                                std::back_insert_iterator<std::string>>> facet;
    std::ios str(nullptr);

    facet.put(std::back_inserter(s), str,
                                     str.fill(), static_cast<unsigned long>(n));
}

int main()
{
    std::string str = "ID: ";
    int id = 123;

    append_int(str, id);

    std::cout << str; // ID: 123
}
0x499602D2
la source
2
  • std :: ostringstream
#include <sstream>

std::ostringstream s;
s << "John " << age;
std::string query(s.str());
  • std :: to_string (C ++ 11)
std::string query("John " + std::to_string(age));
  • boost :: lexical_cast
#include <boost/lexical_cast.hpp>

std::string query("John " + boost::lexical_cast<std::string>(age));
Isma Rekathakusuma
la source
Lequel est le plus rapide?
GyuHyeon Choi
2

Il y a une fonction que j'ai écrite, qui prend le nombre entier comme paramètre et le convertit en chaîne littérale. Cette fonction dépend d'une autre fonction qui convertit un seul chiffre en son équivalent char:

char intToChar(int num)
{
    if (num < 10 && num >= 0)
    {
        return num + 48;
        //48 is the number that we add to an integer number to have its character equivalent (see the unsigned ASCII table)
    }
    else
    {
        return '*';
    }
}

string intToString(int num)
{
    int digits = 0, process, single;
    string numString;
    process = num;

    // The following process the number of digits in num
    while (process != 0)
    {
        single  = process % 10; // 'single' now holds the rightmost portion of the int
        process = (process - single)/10;
        // Take out the rightmost number of the int (it's a zero in this portion of the int), then divide it by 10
        // The above combination eliminates the rightmost portion of the int
        digits ++;
    }

    process = num;

    // Fill the numString with '*' times digits
    for (int i = 0; i < digits; i++)
    {
        numString += '*';
    }


    for (int i = digits-1; i >= 0; i--)
    {
        single = process % 10;
        numString[i] = intToChar ( single);
        process = (process - single) / 10;
    }

    return numString;
}
Reda Lahdili
la source
1

Avec la bibliothèque {fmt} :

auto result = fmt::format("{}{}", name, age);

Un sous-ensemble de la bibliothèque est proposé pour la normalisation en tant que formatage de texte P0645 et, s'il est accepté, ce qui précède deviendra:

auto result = std::format("{}{}", name, age);

Avertissement : je suis l'auteur de la bibliothèque {fmt}.

vitaut
la source
0

En tant que doublure: name += std::to_string(age);

ant_dev
la source
3
C'est le même code que dans la réponse 0x499602D2.
BDL