【问题标题】:How to concatenate a std::string and an int如何连接 std::string 和 int
【发布时间】:2010-09-16 13:06:09
【问题描述】:

我认为这会很简单,但它提出了一些困难。如果我有

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

如何将它们组合成一个字符串"John21"

【问题讨论】:

  • Herb Sutter 有一篇关于这个主题的好文章:"The String Formatters of Manor Farm"。他涵盖了Boost::lexical_caststd::stringstreamstd::strstream(已弃用)和sprintfsnprintf
  • 让我补充一下:我试过 'str = "hi"; str += 5; cout

标签: c++ integer concatenation stdstring


【解决方案1】:

按字母顺序:

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 &lt;string&gt; 中)
  3. 安全、快速;需要FastFormat,必须编译;大多数/所有平台
  4. 同上
  5. 安全、快速;需要the {fmt} library,既可以编译也可以在仅头文件模式下使用;大多数/所有平台
  6. 安全、缓慢、冗长;需要 #include &lt;sstream&gt;(来自标准 C++)
  7. 脆弱(您必须提供足够大的缓冲区)、快速且冗长; itoa() 是一个非标准扩展,不保证适用于所有平台
  8. 脆弱(您必须提供足够大的缓冲区)、快速且冗长;什么都不需要(是标准的 C++);所有平台
  9. 很脆弱(必须提供足够大的缓冲区),probably the fastest-possible conversion,冗长;需要STLSoft(仅标题);大多数/所有平台
  10. safe-ish(在单个语句中不要使用多个 int_to_string() 调用),快速;需要STLSoft(仅标题);仅限 Windows
  11. 是安全的,但速度较慢;需要Poco C++;大多数/所有平台

【讨论】:

  • 除了你gfive的一个链接,你的性能cmet是基于什么的?
  • 这几乎是您从一个答案中获得的全部声誉!你幸运的豆子;)我认为 8 是标准 C(当然也是 C++),但可能值得区分。
  • 2.很慢,因为 std::to_string(age) 创建了一个附加到结果的临时字符串。
  • 如果您使用的是 Arduino,也可以使用String(number)
  • 我会添加 snprintf 也可能是 sprintf 的 instread。
【解决方案2】:

在 C++11 中,可以使用std::to_string,例如:

auto result = name + std::to_string( age );

【讨论】:

  • 和以前一样。
【解决方案3】:

如果您有 Boost,则可以使用 boost::lexical_cast&lt;std::string&gt;(age) 将整数转换为字符串。

另一种方法是使用字符串流:

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

第三种方法是使用 C 库中的 sprintfsnprintf

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

其他海报建议使用itoa。这不是标准功能,因此如果您使用它,您的代码将无法移植。有些编译器不支持它。

【讨论】:

  • 请注意,不保证 snprintf 以空值终止字符串。这是确保它有效的一种方法:
     char buffer[128];缓冲区[sizeof(buffer)-1] = '\0'; snprintf(buffer, sizeof(buffer)-1, "%s%d", name.c_str(), age); std::cout 
  • 我倾向于从不使用 sprintf,因为这会导致缓冲区溢出。上面的例子是一个很好的例子,如果名称很长,使用 sprintf 会不安全。
  • 请注意, snprintf 同样是非标准的 c++(就像您提到的 itoa)。取自 c99
  • @terson:我看到答案中没有出现sprintf,只有snprintf
【解决方案4】:
#include <iostream>
#include <sstream>

std::ostringstream o;
o << name << age;
std::cout << o.str();

【讨论】:

  • 这个很好,BYT头文件是sstream
【解决方案5】:
#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 使用后,对吧?
  • 按值返回是可以的,即使字符串对象已经超出范围,stackoverflow.com/a/3977119/5393174
  • 链接已损坏:“页面未找到”
【解决方案6】:

这是最简单的方法:

string s = name + std::to_string(age);

【讨论】:

  • 这是 C++11 后的解决方案!
【解决方案7】:

如果你有 C++11,你可以使用std::to_string

例子:

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

name += std::to_string(age);

std::cout << name;

输出:

John21

【讨论】:

  • 如您所见,在 VC++ 2010 中将是 name += std::to_string(static_cast&lt;long long&gt;(age)); here
  • @neonmate name += std::to_string(age + 0LL); 怎么样?
  • 很好的解决方案。谢谢
【解决方案8】:

在我看来,最简单的答案是使用sprintf 函数:

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

【讨论】:

  • snprintf 可能很棘手(主要是因为它在某些情况下可能不包含空字符),但我更喜欢这样做以避免 sprintf 缓冲区溢出潜在问题。
  • sprintf(char*, const char*, ...) 在您将 std::string 传递给 %s 时,在某些版本的编译器上会失败。不过,并非全部(这是未定义的行为),它可能取决于字符串长度(SSO)。请使用 .c_str()
  • 加上 sprintf 会发生缓冲区溢出,因此可能会注入代码
【解决方案9】:
#include <string>
#include <sstream>
using namespace std;
string concatenate(std::string const& name, int i)
{
    stringstream s;
    s << name << i;
    return s.str();
}

【讨论】:

    【解决方案10】:
    #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;
    

    Googled [并经过测试:p]

    【讨论】:

      【解决方案11】:

      这个问题可以通过多种方式解决。我将通过两种方式展示它:

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

      【讨论】:

      • 哪个更快?
      【解决方案12】:

      在 C++20 中,您将能够做到:

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

      同时你可以使用the {fmt} librarystd::format是基于:

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

      免责声明:我是 {fmt} 库和 C++20 std::format 的作者。

      【讨论】:

        【解决方案13】:

        如果您想使用+ 连接任何具有输出运算符的内容,您可以提供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
        

        这不是最有效的方式,但您不需要最有效的方式,除非您在循环内进行大量连接。

        【讨论】:

        • 如果我尝试添加到整数或整数和双精度,会调用这个函数吗?我想知道这个解决方案是否会覆盖通常的添加...
        • 该运算符返回一个std::string,因此在字符串不能转换为所需类型的表达式中不会是候选对象。例如,此 operator+ 不适合用于 int x = 5 + 7; 中的 +。考虑到所有因素,如果没有非常令人信服的理由,我不会定义这样的运算符,但我的目标是提供与其他人不同的答案。
        • 你是对的(我刚刚测试过......)。当我尝试执行 string s = 5 + 7 之类的操作时,我收到错误 invalid conversion from ‘int’ to ‘const char’*
        • 对于大多数用例,使用将左侧或右侧操作数绑定到字符串(包括std::stringstd::string_viewconst char *)的模板就足够了。
        【解决方案14】:

        如果您使用的是 MFC,则可以使用 CString

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

        托管 C++ 也有一个 string formatter.

        【讨论】:

          【解决方案15】:

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

          【讨论】:

          • 为什么使用预处理器#define 而不是template?使用可变参数模板,甚至可以传入多个令牌。但我很犹豫是否要使用它,因为 &lt;&lt; 操作数的输出上的 static_cast 回到 std::ostringstream 有点不安全。这是一个约定,所有的输出器都返回一个指向原始流对象的引用,但这在标准中没有得到保证。
          • 您正在评论一个 12 岁的答案。我们现在有可变参数模板。我现在可能会选择github.com/fmtlib/fmt
          【解决方案16】:

          由于一个与 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) 也有效
          【解决方案17】:

          有更多选项可用于将整数(或其他数字对象)与字符串连接起来。是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 声称是fastest option for integer to string 转换之一。

          【讨论】:

            【解决方案18】:
            • 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));
            

            【讨论】:

            • 哪个最快?
            【解决方案19】:

            作为一个班轮:name += std::to_string(age);

            【讨论】:

              【解决方案20】:

              这是一个如何使用 IOStreams 库中的解析和格式化方面将 int 附加到字符串的实现。

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

              【讨论】:

                【解决方案21】:

                常见答案:itoa()

                这很糟糕。 itoa 是非标准的,正如 here 指出的那样。

                【讨论】:

                【解决方案22】:

                您可以使用下面给出的简单技巧将 int 连接到字符串,但请注意,这仅适用于整数为单个数字的情况。否则,将整数逐位添加到该字符串。

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

                【讨论】:

                  【解决方案23】:

                  我写了一个函数,它以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;
                  }
                  

                  【讨论】:

                    【解决方案24】:

                    在 C++ 20 中,您可以拥有一个可变参数 lambda,它可以在几行中将任意可流式传输类型连接到一个字符串:

                    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 对象的字符串缓冲区在下次调用 lambda 时为空。

                    【讨论】:

                    • 请注意,与此处介绍的其他一些解决方案不同,此 lambda 不会是线程安全的/可重入的。这可以通过将 ostringstream 生命周期移动到 lambda 主体中来解决,而且我不认为将它初始化在捕获列表中没有任何好处(无论哪种方式都不会有任何内存重用,由于搬家)。
                    猜你喜欢
                    • 1970-01-01
                    • 2015-01-24
                    • 2012-03-26
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-11-22
                    相关资源
                    最近更新 更多