如何从fmt::format格式字符串中提取width参数?
Extract Width Parameter from fmt Format String
Problem Description
我需要一种方法从
fmt::format的格式字符串中提取width参数,而不是获取格式化操作后的结果大小(后者可以通过auto size = fmt::formatted_size("{:>5.2f}", 13453453.76345f);轻松实现)。例如,对于
fmt::format("{:>5.2f}", 13.23454f);,希望提取其中的数字5;同时该方法需要支持整数格式字符串,比如fmt::format("{:>4d}", 42);,提取其中的数字4。期望能有类似auto width = get_format_width("{:>5.2f}"); assert(width == 5);的实现方式。
Solution
fmt库本身提供了用于解析格式说明符的底层API,我们可以利用这些API来精准提取width参数,避免自己编写容易出错的字符串解析逻辑。下面是一个可直接使用的实现:
#include <fmt/core.h> #include <fmt/format.h> #include <optional> #include <string_view> #include <cassert> #include <cctype> std::optional<int> get_format_width(std::string_view format_str) { // 定位格式说明符的起始标记':' const size_t colon_pos = format_str.find(':'); if (colon_pos == std::string_view::npos) { // 格式字符串中没有指定格式说明符,无width参数 return std::nullopt; } // 提取从':'到'}'之间的格式说明内容 std::string_view spec_part = format_str.substr(colon_pos + 1); const size_t closing_brace = spec_part.find('}'); if (closing_brace != std::string_view::npos) { spec_part = spec_part.substr(0, closing_brace); } // 使用fmt的解析上下文处理格式说明 fmt::format_parse_context parse_ctx(spec_part); auto spec_it = parse_ctx.begin(); // 跳过格式说明中的前缀字符(对齐、符号、标记等) while (spec_it != parse_ctx.end() && ( *spec_it == '<' || *spec_it == '>' || *spec_it == '^' || // 对齐符 *spec_it == '+' || *spec_it == '-' || *spec_it == ' ' || // 符号标记 *spec_it == '#' // 替代格式标记 )) { ++spec_it; } // 解析连续的数字作为width参数 if (spec_it != parse_ctx.end() && std::isdigit(static_cast<unsigned char>(*spec_it))) { int width_value = 0; while (spec_it != parse_ctx.end() && std::isdigit(static_cast<unsigned char>(*spec_it))) { width_value = width_value * 10 + (*spec_it - '0'); ++spec_it; } return width_value; } // 未找到固定数值的width参数 return std::nullopt; } // 测试示例 int main() { // 浮点数格式测试 assert(get_format_width("{:>5.2f}") == 5); // 整数格式测试 assert(get_format_width("{:>4d}") == 4); // 无width参数的情况 assert(!get_format_width("{:.2f}").has_value()); // 无格式说明符的情况 assert(!get_format_width("{}").has_value()); // 带符号和对齐的复杂格式 assert(get_format_width("{:+<6d}") == 6); return 0; }
How It Works
- 定位格式说明符:先找到格式字符串中的
:标记,确定格式说明部分的起始位置 - 提取格式说明内容:截取从
:到}之间的字符串,这就是我们需要解析的格式规则部分 - 跳过前缀字符:格式说明中可能包含对齐符(
>、<、^)、符号标记(+、-、)等前缀,我们需要先跳过这些字符,找到width参数的起始位置 - 解析width数值:读取连续的数字字符,转换为整数,这就是我们要提取的width参数
- 边界情况处理:如果没有格式说明符、没有固定数值的width参数,都会返回
std::nullopt
Notes
- 这个实现不支持动态width参数(比如
{:*>{}}这种使用其他参数作为width的情况),因为这类width不是固定在格式字符串中的数值 - 代码适配fmt 7.x及以上版本,确保编译时链接对应版本的fmt库
内容的提问来源于stack exchange,提问作者user23573
相关产品推荐
相关产品推荐

