Как объединить std :: string и int

Я думал, что это будет действительно просто, но это вызывает некоторые трудности. Если у меня есть

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

Как их объединить, чтобы получить одну строку "John21"?


person Obediah Stane    schedule 10.10.2008    source источник
comment
У Херба Саттера есть хорошая статья на эту тему: Строковые форматеры усадебной фермы. Он охватывает Boost::lexical_cast, std::stringstream, std::strstream (который устарел) и sprintf vs. snprintf.   -  person Fred Larson    schedule 10.10.2008
comment
Позвольте мне добавить к этому: я пробовал str = hi; стр + = 5; cout ‹---------------- str; ' и не увидел никакого эффекта. Оказывается, это вызывает оператор + = (char) и добавляет непечатаемый символ.   -  person daveagp    schedule 26.10.2014


Ответы (23)


В алфавитном порядке:

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. безопасно, но медленно; требуется Boost (только заголовок); большинство / все платформы
  2. безопасно, требует C ++ 11 (to_string () уже включен в #include <string>)
  3. безопасно и быстро; требуется FastFormat, который необходимо скомпилировать; большинство / все платформы
  4. (то же)
  5. безопасно и быстро; требуется библиотека {fmt}, которую можно скомпилировать или использовать в режиме только заголовков; большинство / все платформы
  6. безопасный, медленный и подробный; требуется #include <sstream> (из стандартного C ++)
  7. является хрупким (необходимо предоставить достаточно большой буфер), быстрым и подробным; itoa () - нестандартное расширение, и его доступность для всех платформ не гарантируется.
  8. является хрупким (необходимо предоставить достаточно большой буфер), быстрым и подробным; ничего не требует (это стандартный C ++); все платформы
  9. является хрупким (необходимо предоставить достаточно большой буфер), вероятно, самое быстрое преобразование, подробное; требуется STLSoft (только заголовок); большинство / все платформы
  10. безопасный (вы не используете более одного int_to_string () вызов в одном операторе), быстро; требуется STLSoft (только заголовок); Только для Windows
  11. безопасно, но медленно; требуется Poco C ++; большинство / все платформы
person DannyT    schedule 22.05.2009
comment
Помимо одной ссылки, которую вы дали, на чем вы основываете свои комментарии о производительности? - person JamieH; 23.05.2009
comment
Это почти вся ваша репутация с одного ответа !! Тебе повезло;) Я думаю, что 8 - это стандартный C (конечно, также C ++), но, вероятно, стоит выделить его. - person noelicus; 16.08.2018
comment
2. работает медленно, поскольку std :: to_string (age) создает временную строку, которая добавляется к результату. - person Igor Bukanov; 15.09.2019
comment
Если вы используете Arduino, вы также можете использовать String(number). - person Machado; 19.04.2020
comment
Я бы тоже добавил snprintf, может быть, в sprintf. - person rjhcnf; 13.05.2021
comment
Было бы гораздо лучше добавить сюда ссылку на тест производительности. - person prehistoricpenguin; 24.06.2021

В C ++ 11 вы можете использовать std::to_string, например:

auto result = name + std::to_string( age );
person Jeremy    schedule 08.08.2012

Если у вас есть Boost, вы можете преобразовать целое число в строку с помощью boost::lexical_cast<std::string>(age).

Другой способ - использовать строковые потоки:

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

Третий подход - использовать sprintf или snprintf из библиотеки C.

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

Другие плакаты предлагали использовать itoa. Это НЕ стандартная функция, поэтому ваш код не будет переносимым, если вы ее используете. Есть компиляторы, которые его не поддерживают.

person Jay Conrod    schedule 10.10.2008
comment
Обратите внимание, что snprintf не гарантирует завершение строки нулем. Вот один из способов убедиться, что это работает: ‹pre› char buffer [128]; буфер [размер (буфер) -1] = '\ 0'; snprintf (буфер, sizeof (буфер) -1,% s% d, name.c_str (), возраст); std :: cout ‹* buffer ‹$ std :: endl; ‹/Pre› - person Mr Fooz; 10.10.2008
comment
Я бы никогда не использовал sprintf, поскольку это может привести к переполнению буфера. Приведенный выше пример является хорошим примером, когда использование sprintf было бы небезопасным, если бы имя было очень длинным. - person terson; 11.10.2008
comment
обратите внимание, что snprintf также нестандартный C ++ (например, itoa, о котором вы упомянули). это взято из c99 - person Johannes Schaub - litb; 09.02.2009
comment
@terson: Я не вижу в ответе sprintf, только snprintf. - person David Foerster; 03.07.2013

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
string itos(int i) // convert int to string
{
    stringstream s;
    s << i;
    return s.str();
}

Беззастенчиво украдено с http://www.research.att.com/~bs/bs_faq2.html.

person tloach    schedule 10.10.2008
comment
но s - это переменные стека, память s будет освобождена после вызова itos. s должен выделяться из кучи, а free после использования, верно? - person kgbook; 10.09.2018
comment
возврат по значению в порядке, даже если строковый объект вышел за пределы области видимости, stackoverflow.com/a/3977119/5393174 - person kgbook; 10.09.2018
comment
Ссылка не работает: Страница не найдена - person Peter Mortensen; 17.05.2021

Это самый простой способ:

string s = name + std::to_string(age);
person Kevin    schedule 21.12.2014
comment
Это решение после C ++ 11! - person YamHon.CHAN; 18.05.2015

Если у вас C ++ 11, вы можете использовать std::to_string.

Пример:

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

name += std::to_string(age);

std::cout << name;

Выход:

John21
person 0x499602D2    schedule 27.05.2013
comment
Это будет name += std::to_string(static_cast<long long>(age)); в VC ++ 2010, как вы можете видеть здесь - person neonmate; 27.05.2014
comment
@neonmate Как насчет name += std::to_string(age + 0LL); вместо этого? - person chux - Reinstate Monica; 07.10.2016

Мне кажется, что самый простой ответ - использовать функцию sprintf:

sprintf(outString,"%s%d",name,age);
person user12576    schedule 10.10.2008
comment
snprintf может быть сложным (в основном потому, что он потенциально может не включать нулевой символ в определенных ситуациях), но я предпочитаю это, чтобы избежать потенциальных проблем переполнения буфера sprintf. - person terson; 11.10.2008
comment
sprintf (char *, const char *, ...) завершится ошибкой в ​​некоторых версиях компиляторов, когда вы передадите std :: string в% s. Однако не все (это неопределенное поведение), и это может зависеть от длины строки (SSO). Пожалуйста, используйте .c_str () - person MSalters; 13.10.2008
comment
плюс sprintf подвержен переполнению буфера, поэтому возможна инъекция кода - person Jean-François Fabre; 16.05.2019

#include <sstream>

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

Тогда ваше использование будет выглядеть примерно так

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

Погуглил [и проверил: p]

person Zing-    schedule 10.10.2008

Эту проблему можно решить разными способами. Я покажу это двумя способами:

  1. Преобразуйте число в строку, используя to_string(i).

  2. Использование строковых потоков.

    Код:

    #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;
    }
    
person lohith99    schedule 29.06.2018
comment
Какой из них быстрее? - person ghchoi; 18.02.2020

В C ++ 20 вы сможете:

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

А пока вы можете использовать библиотеку {fmt}, std::format основана на:

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

Заявление об ограничении ответственности: я являюсь автором библиотеки {fmt} и C ++ 20 std::format.

person vitaut    schedule 29.04.2018

Если вы хотите использовать + для конкатенации всего, что имеет оператор вывода, вы можете предоставить версию шаблона operator+:

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

Затем вы можете просто написать свои конкатенации:

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

Выход:

the answer is 42

Это не самый эффективный способ, но вам не нужен самый эффективный способ, если вы не выполняете много конкатенации внутри цикла.

person uckelman    schedule 03.11.2011
comment
Если я попытаюсь добавить к целым числам или к целому и двойному, будет ли вызываться эта функция? Мне интересно, переопределит ли это решение обычные дополнения ... - person Hilder Vitor Lima Pereira; 14.01.2016
comment
Оператор возвращает std::string, поэтому не будет кандидатом в выражения, в которых строка не может быть преобразована в нужный тип. Например, этот operator+ не может использоваться для + в int x = 5 + 7;. Учитывая все обстоятельства, я бы не стал определять такой оператор без очень веской причины, но моей целью было предложить ответ, отличный от других. - person uckelman; 15.01.2016
comment
Вы правы (я только что проверил ...). И когда я попытался сделать что-то вроде string s = 5 + 7, я получил ошибку недопустимое преобразование из «int» в «const char» * - person Hilder Vitor Lima Pereira; 15.01.2016
comment
В большинстве случаев использования шаблонов, которые связывают левый или правый операнд со строкой (которая включает std::string, std::string_view и const char *), должно быть достаточно. - person Kai Petzke; 14.09.2020

Если вы используете MFC, вы можете использовать CString

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

Управляемый C ++ также имеет средство форматирования строк.

person bsruth    schedule 10.10.2008

Std :: ostringstream - хороший метод, но иногда этот дополнительный трюк может оказаться полезным при преобразовании форматирования в однострочное:

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

Теперь вы можете форматировать строки следующим образом:

int main() {
    int i = 123;
    std::string message = MAKE_STRING("i = " << i);
    std::cout << message << std::endl; // prints: "i = 123"
}
person Pyry Jahkola    schedule 10.10.2008
comment
Зачем использовать препроцессор #define вместо template? С помощью вариативных шаблонов можно было бы передать даже несколько токенов. Но я не решаюсь использовать это, поскольку static_cast обратно к std::ostringstream на выходе операнда << немного небезопасно. По соглашению все средства вывода возвращают ссылку на исходный объект потока, но в стандарте это нигде не гарантируется. - person Kai Petzke; 14.09.2020
comment
Вы комментируете ответ 12-летней давности. Теперь у нас есть вариативные шаблоны. Я бы, наверное, сейчас выбрал github.com/fmtlib/fmt. - person Pyry Jahkola; 15.10.2020

Поскольку вопрос, связанный с Qt, был закрыт в пользу этого, вот как это сделать с помощью Qt:

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

Строковая переменная теперь имеет значение someIntVariable вместо% 1 и значение someOtherIntVariable в конце.

person leinir    schedule 10.08.2011
comment
QString (Something) + QString :: number (someIntVariable) также работает - person gremwell; 07.08.2017

Есть больше вариантов, которые можно использовать для объединения целого числа (или другого числового объекта) со строкой. Это 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);
}

и Карма из 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 утверждает, что является одним из самый быстрый вариант преобразования целого числа в строку.

person mloskot    schedule 04.10.2010

В один лайнер: name += std::to_string(age);

person ant_dev    schedule 30.03.2020

Вот реализация того, как добавить int к строке с помощью аспектов синтаксического анализа и форматирования из библиотеки 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
}
person 0x499602D2    schedule 25.11.2013

Общий ответ: itoa ()

Это плохо. itoa является нестандартным, как указано здесь.

person Tom Ritter    schedule 10.10.2008
comment
itoa нестандартен: http://stackoverflow.com/questions/190229/where-is-the-itoa-function-in-linux - person David Dibben; 10.10.2008

  • 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));
person Isma Rekathakusuma    schedule 03.08.2018
comment
Какой самый быстрый? - person ghchoi; 18.02.2020

Вы можете объединить int в строку, используя приведенный ниже простой трюк, но обратите внимание, что это работает только тогда, когда целое число состоит из одной цифры. В противном случае добавьте к этой строке целое число за цифрой.

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

Output:  John5
person Sukhbir    schedule 28.09.2016

Я написал функцию, которая принимает в качестве параметра число int и преобразует его в строковый литерал. Эта функция зависит от другой функции, которая преобразует одну цифру в ее символьный эквивалент:

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;
}
person Reda Lahdili    schedule 28.08.2013

В C ++ 20 у вас может быть переменная лямбда, которая объединяет произвольные потоковые типы в строку в несколько строк:

auto make_string=[os=std::ostringstream{}](auto&& ...p) mutable 
{ 
  (os << ... << std::forward<decltype(p)>(p) ); 
  return std::move(os).str();
};

int main() {
std::cout << make_string("Hello world: ",4,2, " is ", 42.0);
}

см. https://godbolt.org/z/dEe9h75eb

использование move (os) .str () гарантирует, что строковый буфер объекта ostringstream будет пустым при следующем вызове лямбды.

person PeterSom    schedule 12.05.2021
comment
Обратите внимание, что эта лямбда не будет потокобезопасной / реентерабельной, в отличие от некоторых других решений, представленных здесь. Эту проблему можно решить, переместив время жизни ostringstream в тело лямбда-выражения, и я не думаю, что есть какая-то польза от сохранения его инициализированным в списке захвата (в любом случае повторного использования памяти не будет, в связи с переездом). - person Sean Middleditch; 12.05.2021

person    schedule
comment
это здорово, заголовочный файл BYT sstream - person landerlyoung; 13.01.2017