我必须用sprintf格式化std::string,并将其发送到文件流。我该怎么做呢?
当前回答
我试了一下,用正则表达式。我为int和const字符串实现了它作为一个例子,但你可以添加任何其他类型(POD类型,但有指针,你可以打印任何东西)。
#include <assert.h>
#include <cstdarg>
#include <string>
#include <sstream>
#include <regex>
static std::string
formatArg(std::string argDescr, va_list args) {
std::stringstream ss;
if (argDescr == "i") {
int val = va_arg(args, int);
ss << val;
return ss.str();
}
if (argDescr == "s") {
const char *val = va_arg(args, const char*);
ss << val;
return ss.str();
}
assert(0); //Not implemented
}
std::string format(std::string fmt, ...) {
std::string result(fmt);
va_list args;
va_start(args, fmt);
std::regex e("\\{([^\\{\\}]+)\\}");
std::smatch m;
while (std::regex_search(fmt, m, e)) {
std::string formattedArg = formatArg(m[1].str(), args);
fmt.replace(m.position(), m.length(), formattedArg);
}
va_end(args);
return fmt;
}
下面是一个使用它的例子:
std::string formatted = format("I am {s} and I have {i} cats", "bob", 3);
std::cout << formatted << std::endl;
输出:
我是鲍勃,我有三只猫
其他回答
如果你只想要一个类似printf的语法(不需要自己调用printf),可以看看Boost Format。
下面是@iFreilicht答案的稍微修改版本,更新到c++ 14(使用make_unique函数而不是原始声明),并增加了对std::string参数的支持(基于Kenny Kerr的文章)
#include <iostream>
#include <memory>
#include <string>
#include <cstdio>
template <typename T>
T process_arg(T value) noexcept
{
return value;
}
template <typename T>
T const * process_arg(std::basic_string<T> const & value) noexcept
{
return value.c_str();
}
template<typename ... Args>
std::string string_format(const std::string& format, Args const & ... args)
{
const auto fmt = format.c_str();
const size_t size = std::snprintf(nullptr, 0, fmt, process_arg(args) ...) + 1;
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, fmt, process_arg(args) ...);
auto res = std::string(buf.get(), buf.get() + size - 1);
return res;
}
int main()
{
int i = 3;
float f = 5.f;
char* s0 = "hello";
std::string s1 = "world";
std::cout << string_format("i=%d, f=%f, s=%s %s", i, f, s0, s1) << "\n";
}
输出:
i = 3, f = 5.000000, s = hello world
如果需要,可以随意将这个答案与原始答案合并。
c++ 20 std::格式
它来了!该特性描述在:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0645r9.html,并使用类似python的.format()语法。
我希望它的用法是这样的:
#include <format>
#include <string>
int main() {
std::string message = std::format("The answer is {}.", 42);
}
g++-9 -std=c++2a的GCC 9.1.0仍然不支持它。
现有的fmt库在获得官方支持之前实现了它:https://github.com/fmtlib/fmt,如前所述:std::string格式化,如sprintf:
sudo apt install libfmt-dev
修改源代码以替换:
用<fmt/core.h> .h格式化> Std::format转换为fmt::format
main.cpp
#include <string>
#include <iostream>
#include <fmt/core.h>
int main() {
std::string message = fmt::format("The answer is {}.", 42);
std::cout << message << std::endl;
}
编译并运行:
g++ -std=c++11 -o main.out main.cpp -lfmt
./main.out
输出:
The answer is 42.
API将添加一个新的std::format头文件:
建议的格式化API定义在新的header <format>中,应该不会对现有代码产生影响。
十六进制格式{:x}
c++十六进制成本值?
前导零{:03}
用c++输出操作符打印前导零?
左对齐{:<},右对齐{:>},中对齐{:^}
打印cout时c++对齐<<
浮点精度{:.2}
我如何打印一个双值与全精度使用cout? 在c++中设置默认浮点打印精度
在正数{:+}上显示符号
如何打印正数与前缀+在c++
将布尔值显示为true和false: {:}
在c++中将bool转换为文本
我不喜欢把事情搞复杂。这是基于iFreilicht的答案,但我减少了一些噪音,使它更有效。请注意,如果您计划在接口中使用此功能,可能会添加一些模糊输入检查。
#include <iostream>
#include <string>
template<typename... Ts>
std::string string_format( const std::string& format, Ts... Args )
{
const size_t n = std::snprintf( nullptr, 0, format.c_str(), Args ... ) + 1; // Extra space for '\0'
std::string ret(n, '\0');
std::snprintf( &ret.front(), n, format.c_str(), Args... );
return ret;
}
int main()
{
int a = 5;
char c = 'h';
double k = 10.3;
std::cout << string_format("%d, %c, %.2f", a, c, k) << "\n";
}
输出:
5, h, 10.30
试着自己
(*唯一的警告,我发现性能方面是没有办法默认初始化字符串存储。这很遗憾,因为我们不需要在这里将所有的值初始化为“\0”。)
这是谷歌的做法: facebook也以类似的方式:StringPrintf (Apache许可证) 两者都提供了一个方便的StringAppendF。
推荐文章
- 为什么这个结合赋值和相等检查的if语句返回true?
- cplusplus.com给出的错误、误解或坏建议是什么?
- c#:如何获得一个字符串的第一个字符?
- String类中的什么方法只返回前N个字符?
- 找出质数最快的算法是什么?
- 我可以将c#字符串值转换为转义字符串文字吗?
- 在c#中解析字符串为日期时间
- 字符串中的单词大写
- 自定义数字格式字符串始终显示符号
- c++枚举类可以有方法吗?
- string.ToLower()和string.ToLowerInvariant()
- PHP字符串中的花括号
- 如何在Python中拆分这一长行?
- 格式化IO函数(*printf / *scanf)中的转换说明符%i和%d之间的区别是什么?
- 将析构函数设为私有有什么用?