【问题标题】:String.Format alternative in C++ [duplicate]C ++中的String.Format替代方案[重复]
【发布时间】:2012-05-02 08:15:26
【问题描述】:

我没有太多使用 C++ 的经验。相反,我在 C# 中工作得更多,因此,我想通过与我将在那里做的事情相关联来问我的问题。我必须生成特定格式的字符串,我必须将其传递给另一个函数。在 C# 中,我可以通过下面的简单代码轻松生成字符串。

string a = "test";
string b = "text.txt";
string c = "text1.txt";

String.Format("{0} {1} > {2}", a, b, c);

通过生成上述这样的字符串,我应该能够将其传递给system()。但是,system 只接受char*

我在Win32 C++(不是C++/CLI)上,不能使用boost,因为它会包含太多的所有文件,而这个项目本身非常小。 sprintf() 之类的东西对我来说看起来很有用,但 sprintf 不接受 string 作为 abc 参数。有什么建议可以在我的程序中生成这些格式化字符串以传递给系统吗?

【问题讨论】:

  • 您知道 boost 不会向您的二进制文件添加任何依赖项,对吧? (它当然会向源添加依赖项)

标签: c# c++ string string-formatting


【解决方案1】:

C++ 方法是使用std::stringstream 对象:

std::stringstream fmt;
fmt << a << " " << b << " > " << c;

C 方式是使用sprintf

C 方式很难正确,因为:

  • 类型不安全
  • 需要缓冲区管理

当然,如果性能是一个问题,您可能希望退回到 C 方式(假设您正在创建固定大小的百万小 stringstream 对象,然后将它们丢弃)。

【讨论】:

  • system(fmt) 给我一个错误,说在stringstreamchar* 之间没有合适的转换
  • system(fmt.str().c_str()) 可能应该这样做。请注意,至少在 Windows 上,如果您调用 system() 并且即使命令及其参数正确且引用正确,也会出现错误,请将整个内容用引号括起来,它会起作用。
  • 需要注意的两点:1) system 是实现定义的——所以如果你想保持代码的可移植性,请不要使用它。 2)正如其他人所提到的,使用fmt.str().c_str() 来获取字符串的char *(C 风格字符串)表示。
【解决方案2】:

为了完整起见,您可以使用std::stringstream

#include <iostream>
#include <sstream>
#include <string>

int main() {
    std::string a = "a", b = "b", c = "c";
    // apply formatting
    std::stringstream s;
    s << a << " " << b << " > " << c;
    // assign to std::string
    std::string str = s.str();
    std::cout << str << "\n";
}

或者(在这种情况下)std::string 自己的字符串连接功能:

#include <iostream>
#include <string>

int main() {
    std::string a = "a", b = "b", c = "c";
    std::string str = a + " " + b + " > " + c;
    std::cout << str << "\n";
}

供参考:


如果你真的想走 C 路。你在这里:

#include <iostream>
#include <string>
#include <vector>
#include <cstdio>

int main() {
    std::string a = "a", b = "b", c = "c";
    const char fmt[] = "%s %s > %s";
    // use std::vector for memory management (to avoid memory leaks)
    std::vector<char>::size_type size = 256;
    std::vector<char> buf;
    do {
        // use snprintf instead of sprintf (to avoid buffer overflows)
        // snprintf returns the required size (without terminating null)
        // if buffer is too small initially: loop should run at most twice
        buf.resize(size+1);
        size = std::snprintf(
                &buf[0], buf.size(),
                fmt, a.c_str(), b.c_str(), c.c_str());
    } while (size+1 > buf.size());
    // assign to std::string
    std::string str(buf.begin(), buf.begin()+size);
    std::cout << str << "\n";
}

供参考:


然后是Boost Format Library。为了您的示例:

#include <iostream>
#include <string>
#include <boost/format.hpp>

int main() {
    std::string a = "a", b = "b", c = "c";
    // apply format
    boost::format fmt = boost::format("%s %s > %s") % a % b % c; 
    // assign to std::string
    std::string str = fmt.str();
    std::cout << str << "\n";
}

【讨论】:

  • OP 提到不能使用boost:/
【解决方案3】:

除了其他人建议的选项之外,我还可以推荐 fmt library,它实现了类似于 Python 中的 str.format 和 C# 中的 String.Format 的字符串格式。这是一个例子:

std::string a = "test";
std::string b = "text.txt";
std::string c = "text1.txt";
std::string result = fmt::format("{0} {1} > {2}", a, b, c);

免责声明:我是这个库的作者。

【讨论】:

    【解决方案4】:

    您可以将sprintfstd::string.c_str() 结合使用。

    c_str() 返回 const char* 并与 sprintf 一起使用:

    string a = "test";
    string b = "text.txt";
    string c = "text1.txt";
    char* x = new char[a.length() + b.length() + c.length() + 32];
    
    sprintf(x, "%s %s > %s", a.c_str(), b.c_str(), c.c_str() );
    
    string str = x;
    delete[] x;
    

    如果您知道大小,也可以使用预先分配的 char 数组:

    string a = "test";
    string b = "text.txt";
    string c = "text1.txt";
    char x[256];
    
    sprintf(x, "%s %s > %s", a.c_str(), b.c_str(), c.c_str() );
    

    【讨论】:

    • {0}、{1}、{2} 不应该是 %s 吗?我应该在操作后删除这个 char* x 还是没关系?
    • sprintf 中的 {0}、{1}、{2} 是什么?什么是删除[x]?
    • @user1240679 这是一个错字,se 更正版本。如果分配了new,你应该删除char*,否则它是内存泄漏。
    • @LuchianGrigore:我强烈建议将std::vectorsnprintf 结合使用,以避免泄漏和缓冲区溢出。见snprintf
    【解决方案5】:

    为了完整起见,提升方式是使用boost::format

    cout << boost::format("%s %s > %s") % a % b % c;
    

    任你选。 boost 解决方案具有sprintf 格式的类型安全优势(对于那些发现&lt;&lt; 语法有点笨拙的人)。

    【讨论】:

      【解决方案6】:

      如前所述,C++ 方式是使用字符串流。

      #include <sstream>
      
      string a = "test";
      string b = "text.txt";
      string c = "text1.txt";
      
      std::stringstream ostr;
      ostr << a << " " << b << " > " << c;
      

      请注意,您可以像这样从字符串流对象中获取 C 字符串。

      std::string formatted_string = ostr.str();
      const char* c_str = formatted_string.c_str();
      

      【讨论】:

        【解决方案7】:

        您可以只连接字符串并构建命令行。

        std::string command = a + ' ' + b + " > " + c;
        system(command.c_str());
        

        您不需要任何额外的库。

        【讨论】:

        • 据我所知,C++ 不会对此进行优化,因此这会复制每个操作的字符串,首先创建a + ' ',然后创建a + ' ' + b,等等。
        猜你喜欢
        • 2019-04-22
        • 2015-07-05
        • 1970-01-01
        • 2017-12-04
        • 2020-09-20
        • 2018-11-14
        • 2020-04-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多