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


655

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

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

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


У Херба Саттера есть хорошая статья на эту тему: «Строковые форматеры усадебной фермы» . Он охватывает Boost::lexical_cast, std::stringstream, std::strstream(который не рекомендуется), и sprintfпротив snprintf.
Фред Ларсон

Позвольте мне добавить к этому: я попробовал 'str = "hi"; str + = 5; cout << str; ' и не видел эффекта. Оказывается, это вызывает оператор + = (char) и добавляет непечатный символ.
daveagp

Ответы:


1126

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

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. safe-ish (вы не используете более одного вызова int_to_string () в одном выражении), быстро; требует STLSoft (только заголовок); Windows , только
  11. безопасно, но медленно; требует Poco C ++ ; большинство / все платформы

13
Помимо той ссылки, которую вы получили, на чем основаны ваши комментарии по эффективности?
JamieH

2
Это почти вся ваша репутация от одного ответа! Вам, боб, повезло;) Я думаю, что 8 - это стандартный C (конечно, C ++), но, вероятно, его стоит отличить.
noelicus

2. работает медленно, так как std :: to_string (age) создает временную строку, которая добавляется к результату.
Игорь Буканов

Если вы на Arduino, вы также можете использовать String(number).
Мачадо


85

Если у вас есть 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. Это НЕ стандартная функция, поэтому ваш код не будет переносимым, если вы его используете. Есть компиляторы, которые не поддерживают это.


Обратите внимание, что snprintf не гарантирует нулевое завершение строки. Вот один из способов убедиться, что он работает: <pre> char buffer [128]; buffer [sizeof (buffer) -1] = '\ 0'; snprintf (буфер, sizeof (буфер) -1, "% s% d", name.c_str (), age); std :: cout << buffer << std :: endl; </ pre>
Мистер Фуз

Моя тенденция состоит в том, чтобы никогда не использовать sprintf, поскольку это может привести к переполнению буфера. Приведенный выше пример является хорошим примером, когда использование sprintf было бы небезопасно, если имя было очень длинным.
terson

обратите внимание, что snprintf в равной степени нестандартный c ++ (например, itoa, о котором вы упомянули). взято из c99
Йоханнес Шауб -

@terson: Я не вижу sprintfв ответе только случая snprintf.
Дэвид Фёрстер


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();
}

Бесстыдно похищен с http://www.research.att.com/~bs/bs_faq2.html .


но s это переменная стека, память sбудет свободна после вызова itos. sнадо выделять из кучи, а freeпосле использования, верно?
кгбук

1
возврат по значению в порядке, даже если строковый объект вышел из области видимости, stackoverflow.com/a/3977119/5393174
kgbook


23

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

Пример:

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

name += std::to_string(age);

std::cout << name;

Вывод:

John21

2
Это было бы name += std::to_string(static_cast<long long>(age));в VC ++ 2010, как вы можете видеть здесь
новорожденный

@neonmate Как насчет name += std::to_string(age + 0LL);этого?
chux - Восстановить Монику

18

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

sprintf(outString,"%s%d",name,age);

1
snprintf может быть сложным (в основном потому, что в некоторых ситуациях он может не включать нулевой символ), но я предпочитаю избегать переполнения буфера sprintf потенциальными проблемами.
terson

3
sprintf (char *, const char *, ...) не будет работать в некоторых версиях компиляторов, когда вы передаете std :: string в% s. Не все, хотя (это неопределенное поведение), и это может зависеть от длины строки (SSO). Пожалуйста, используйте .c_str ()
MSalters

плюс sprintf подвержен переполнению буфера, поэтому возможна инъекция кода
Жан-Франсуа Фабр

15
#include <string>
#include <sstream>
using namespace std;
string concatenate(std::string const& name, int i)
{
    stringstream s;
    s << name << i;
    return s.str();
}

11
#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]


10

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

  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;
    }

Какой из них быстрее?
GyuHyeon Choi

7

Если вы хотите использовать +для объединения всего, что имеет оператор вывода, вы можете предоставить шаблонную версию 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

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


Если я попытаюсь добавить к целым числам или целому числу и двойному, будет ли вызываться эта функция? Мне интересно, будет ли это решение переопределять обычные дополнения ...
Хильдер Витор Лима Перейра

Оператор возвращает a std::string, поэтому не будет кандидатом в выражения, где строка не может быть преобразована в нужный тип. Например, это operator+не может быть использовано для +в int x = 5 + 7;. Учитывая все обстоятельства, я бы не определить оператор , как это без очень веских причин, но моя цель состояла в том, чтобы предложить другой ответ от других.
Uckelman

Вы правы (я только что проверил это ...). И когда я попытался сделать что-то вроде строки s = 5 + 7 , я получил неверное преобразование ошибки из 'int' в 'const char ' *
Хильдер Витор Лима Перейра


4

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"
}

4

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

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

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


QString ("Something") + QString :: number (someIntVariable) также работает
gremwell

3

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



3

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

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

Output:  John5

2

Вот реализация того, как добавить 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
}

2
  • станд :: 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));
  • повышение :: lexical_cast
#include <boost/lexical_cast.hpp>

std::string query("John " + boost::lexical_cast<std::string>(age));

Какой из них самый быстрый?
GyuHyeon Choi

2

Я написал функцию, которая принимает число 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;
}

1

С библиотекой {fmt} :

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

Подмножество библиотеки предлагается для стандартизации как форматирование текста P0645, и, если оно будет принято, приведенное выше станет:

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

Отказ от ответственности : я являюсь автором библиотеки {fmt}.


0

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


3
Это тот же код, что и в ответе 0x499602D2.
BDL
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.