¿Cómo concatenar un std :: string y un int?

655

Pensé que esto sería muy simple, pero presenta algunas dificultades. Si tengo

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

¿Cómo los combino para obtener una sola cadena "John21"?

Obediah Stane
fuente
Herb Sutter tiene un buen artículo sobre este tema: "The String Formatters of Manor Farm" . Se cubre Boost::lexical_cast, std::stringstream, std::strstream(que está en desuso), y sprintffrente snprintf.
Fred Larson
Permítanme agregar a esto: intenté 'str = "hola"; str + = 5; cout << str; ' Y no vio ningún efecto. Resulta que esto llama operador + = (char) y agrega un carácter no imprimible.
daveagp

Respuestas:

1126

En orden alfabético:

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. es seguro pero lento; requiere Boost (solo encabezado); la mayoría / todas las plataformas
  2. es seguro, requiere C ++ 11 ( to_string () ya está incluido en #include <string>)
  3. es seguro y rápido; requiere FastFormat , que debe compilarse; la mayoría / todas las plataformas
  4. ( ídem )
  5. es seguro y rápido; requiere la biblioteca {fmt} , que puede compilarse o usarse en modo de solo encabezado; la mayoría / todas las plataformas
  6. seguro, lento y detallado; requiere #include <sstream>(del estándar C ++)
  7. es frágil (debe suministrar un búfer lo suficientemente grande), rápido y detallado; itoa () es una extensión no estándar y no se garantiza que esté disponible para todas las plataformas
  8. es frágil (debe suministrar un búfer lo suficientemente grande), rápido y detallado; no requiere nada (es estándar C ++); todas las plataformas
  9. es frágil (debe proporcionar un búfer lo suficientemente grande), probablemente la conversión más rápida posible , detallada; requiere STLSoft (solo encabezado); la mayoría / todas las plataformas
  10. safe-ish (no usa más de una llamada int_to_string () en una sola declaración), rápido; requiere STLSoft (solo encabezado); Solo para Windows
  11. es seguro pero lento; requiere Poco C ++ ; la mayoría / todas las plataformas
DannyT
fuente
13
Además del único enlace que has dado, ¿en qué basas tus comentarios de rendimiento?
JamieH
2
¡Esa es casi toda tu reputación con una sola respuesta! Tienes suerte;) Creo que 8 es C estándar (por supuesto también C ++), pero probablemente valga la pena diferenciarlo.
noelicus
2. es lento ya que std :: to_string (age) crea una cadena temporal que se agrega al resultado.
Igor Bukanov
Si estás en Arduino, también puedes usarlo String(number).
Machado
267

En C ++ 11, puede usar std::to_string, por ejemplo:

auto result = name + std::to_string( age );
Jeremy
fuente
Me gusta este, simple. Gracias.
truthadjustr
85

Si tiene Boost, puede convertir el entero en una cadena usando boost::lexical_cast<std::string>(age).

Otra forma es usar cadenas de cadena:

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

Un tercer enfoque sería usar sprintfo snprintfde la biblioteca C.

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

Otros carteles sugirieron usar itoa. Esta NO es una función estándar, por lo que su código no será portátil si lo usa. Hay compiladores que no lo admiten.

Jay Conrod
fuente
Tenga en cuenta que snprintf no garantiza la terminación nula de la cadena. Aquí hay una forma de asegurarse de que funciona: <pre> char buffer [128]; buffer [sizeof (buffer) -1] = '\ 0'; snprintf (buffer, sizeof (buffer) -1, "% s% d", nombre.c_str (), edad); std :: cout << buffer << std :: endl; </pre>
Mr Fooz el
Mi tendencia sería nunca usar sprintf, ya que esto puede provocar desbordamientos de búfer. El ejemplo anterior es un buen ejemplo en el que usar sprintf no sería seguro si el nombre fuera muy largo.
terson
tenga en cuenta que snprintf es c ++ igualmente no estándar (como itoa, que usted menciona). está tomado de c99
Johannes Schaub - litb
@terson: No veo ninguna ocurrencia sprintfen la respuesta, solo snprintf.
David Foerster
80
#include <iostream>
#include <sstream>

std::ostringstream o;
o << name << age;
std::cout << o.str();
Ben Hoffstein
fuente
2
esto es genial, el archivo de encabezado BYT es corriente
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();
}

Descaradamente robado de http://www.research.att.com/~bs/bs_faq2.html .

tloach
fuente
pero s es una pila de variables, la memoria de sestará libre después de la invocación itos. sdebe asignar desde el montón, y freedespués de usar, ¿verdad?
kgbook
1
return by value está bien aunque el objeto string se haya salido del alcance, stackoverflow.com/a/3977119/5393174
kgbook
32

Esta es la manera más fácil:

string s = name + std::to_string(age);
Kevin
fuente
8
¡Esta es una solución posterior a C ++ 11!
YamHon.CHAN
23

Si tienes C ++ 11, puedes usarlo std::to_string.

Ejemplo:

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

name += std::to_string(age);

std::cout << name;

Salida:

John21
0x499602D2
fuente
2
Sería name += std::to_string(static_cast<long long>(age));en VC ++ 2010 como puede ver aquí
neonmate
@neonmate ¿Qué tal en su name += std::to_string(age + 0LL);lugar?
chux - Restablecer Monica
18

Me parece que la respuesta más simple es usar la sprintffunción:

sprintf(outString,"%s%d",name,age);
usuario12576
fuente
1
snprintf puede ser complicado (principalmente porque potencialmente no puede incluir el carácter nulo en ciertas situaciones), pero prefiero eso para evitar posibles desbordamientos del búfer sprintf.
terson
3
sprintf (char *, const char *, ...) fallará en algunas versiones de compiladores cuando pase un std :: string a% s. Sin embargo, no todo (es un comportamiento indefinido) y puede depender de la longitud de la cadena (SSO). Utilice .c_str ()
MSalters
más sprintf está sujeto a desbordamientos del búfer, por lo que es posible la inyección de código
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
fuente
11
#include <sstream>

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

Entonces su uso se vería así

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

Buscado en Google [y probado: p]

Gusto-
fuente
10

Este problema se puede hacer de muchas maneras. Lo mostraré de dos maneras:

  1. Convierta el número a cadena usando to_string(i).

  2. Usando secuencias de cadena.

    Código:

    #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
fuente
¿Cuál es más rápido?
GyuHyeon Choi
7

Si desea utilizar +para la concatenación de cualquier cosa que tenga un operador de salida, puede proporcionar una versión de plantilla de operator+:

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

Luego puede escribir sus concatenaciones de una manera directa:

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

Salida:

the answer is 42

Esta no es la forma más eficiente, pero no necesita la forma más eficiente a menos que esté haciendo una gran concatenación dentro de un bucle.

uckelman
fuente
Si trato de agregar enteros o un entero y un doble, ¿se llamará a esta función? Me pregunto si esta solución anulará las adiciones habituales ...
Hilder Vitor Lima Pereira
El operador devuelve a std::string, por lo que no sería un candidato en expresiones donde una cadena no es convertible en el tipo necesario. Por ejemplo, esto operator+no es elegible para ser utilizado +en int x = 5 + 7;. A fin de cuentas, no definiría un operador como este sin una razón muy convincente, pero mi objetivo era ofrecer una respuesta diferente a las demás.
uckelman
Tienes razón (lo acabo de probar ...). Y cuando intenté hacer algo como la cadena s = 5 + 7 , obtuve el error de conversión no válida de 'int' a 'const char ' *
Hilder Vitor Lima Pereira
5

Si está usando MFC, puede usar un CString

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

Managed C ++ también tiene un formateador de cadenas .

bsruth
fuente
4

El std :: ostringstream es un buen método, pero a veces este truco adicional puede ser útil transformando el formato a una línea:

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

Ahora puede formatear cadenas como esta:

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

Como se cerró una pregunta relacionada con Qt a favor de esta, he aquí cómo hacerlo usando Qt:

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

La variable de cadena ahora tiene el valor de someIntVariable en lugar de% 1 y el valor de someOtherIntVariable al final.

leinir
fuente
QString ( "Algo") + QString :: número (someIntVariable) también funciona
gremwell
3

Hay más opciones posibles para concatenar un entero (u otro objeto numérico) con una cadena. Es 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);
}

y 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 afirma ser una de las opciones más rápidas para la conversión de enteros a cadenas .

mloskot
fuente
3

Puede concatenar int a string mediante el siguiente truco simple, pero tenga en cuenta que esto solo funciona cuando el entero es de un solo dígito. De lo contrario, agregue un número entero dígito a dígito a esa cadena.

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

Output:  John5
Sukhbir
fuente
2

Aquí hay una implementación de cómo agregar un int a una cadena usando las facetas de análisis y formato de la biblioteca 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
fuente
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
fuente
¿Cuál es el más rápido?
GyuHyeon Choi
2

Escribí una función que toma el número int como parámetro y lo convierte en un literal de cadena. Esta función depende de otra función que convierte un solo dígito a su equivalente de caracteres:

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
fuente
1

Con la biblioteca {fmt} :

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

Se propone un subconjunto de la biblioteca para la estandarización como formato de texto P0645 y, si se acepta, lo anterior se convertirá en:

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

Descargo de responsabilidad : soy el autor de la biblioteca {fmt}.

vitaut
fuente
0

Como un trazador de líneas: name += std::to_string(age);

ant_dev
fuente
3
Ese es el mismo código que en la respuesta 0x499602D2.
BDL