如何在构建字符串后使用命名占位符对多行原始字符串使用sprintf

how to use sprintf on multiline raw string using named placeholders after building the string?

本文关键字:字符串 原始 sprintf 占位符 构建      更新时间:2023-10-16

在Python、Perl或Ruby中,可以构建一个多行原始字符串(有时称为HERE-DOCUEMNT),然后在构建字符串后,使用命名参数替换字符串中的某些部分(使用%s的令牌)。类似于在字符串上使用sprintf,只是使用名称来帮助指向原始字符串中的这些位置。

这是非常有用的。我只能在C++中完成上面的部分操作,但不知道是否可以使用命名占位符进行字符串替换。

我将在Python中展示一个非常简单的例子,然后在C++中展示我的尝试

s=r"""
begin{document}
title{%(title)s}
This was written on %(date)s
And also updated on %(date)s and so on"""
print s % {"title": "main report","date": "1/1/2015"} 

上面打印

begin{document}
title{main report}
This was written on 1/1/2015
And also updated on 1/1/2015 and so on

在C++中,我能做的最好的事情是:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
using namespace std;
int main()
{
        char buffer [500];
        string s =
R"(
begin{document}
title{%s}
This was written on %s
And also updated on %s and so on
)";    
        snprintf(buffer,500,s.c_str(),"main report","1/1/2015","1/1/2015");
        cout<<buffer<<endl;
        return 0;
}

现在

>g++ -Wall -std=c++0x ./t1.cpp
>./a.out
begin{document}
title{main report}
This was written on 1/1/2015
And also updated on 1/1/2015 and so on

有两个问题:如何在不必手动分配正确大小的缓冲区的情况下最好地执行sprintf,以便能够保存新字符串(在替换后)?

第二个问题,是否可以像Python中的示例那样进行命名替换?这样,如果原始字符串中有许多占位符,并且其中一些占位符可能在不同的位置重复,如上例中的date,则可以同时替换所有占位符。

Q2:不是命名替换,而是将重复项放入变量中,并在需要时使用该变量。

Q1:C++没有用于std::string的内置格式字符串格式化程序。你可以安装一个插件,比如Boost或Poco来获得其中一个。但是像您那样使用snprintf并没有什么问题。

另一种方法是在不格式化的情况下构建字符串:

string title = "main report";
string date = "1-01-2015";
string s = "(n\begin{document}n\title{" + arg + "}nn"
    "This was written on " + date + "nn"
    "And also updated on " + date + " and so onn)";

如果你想坚持使用snprintf,可以调用它来确定缓冲区大小:snprintf(NULL, 0, formatstring, args......);将返回要打印的字节数(所以多分配1)。在你的情况下,我不会打扰你,500已经足够了,如果你真的很担心,你可以检查snprintf的返回值,如果超过500,就会触发错误。

有一个来自facebook的C++库,可以让你进行一些类似printf的命名格式化:

std::map<std::string, std::string> m { {"what", "answerswer"}, {"value", "42"} };
std::cout << vformat("The only {what} is {value}", m);

输出The only answer is 42