c++ - 如何为非字符串的自定义选项值类型处理 Boost::program_options 配置文件中的空格?
问题描述
这个问题涉及Boost::program_options
配置文件中值的解析。
我有一个简单的自定义数据结构:
struct Vector {
double x, y, z;
};
我有一个(x, y, z)
我从另一个 SO 帖子借来的格式“”的 istream 反序列化器:
// https://codereview.stackexchange.com/a/93811/186081
struct Expect {
char expected;
Expect(char expected) : expected(expected) {}
friend std::istream& operator>>(std::istream& is, Expect const& e) {
char actual;
if ((is >> actual) && (actual != e.expected)) {
is.setstate(std::ios::failbit);
}
return is;
}
};
template<typename CharT>
std::basic_istream<CharT> &
operator>>(std::basic_istream<CharT> &in, Vector &v) {
in >> Expect('(') >> v.x
>> Expect(',') >> v.y
>> Expect(',') >> v.z
>> Expect(')');
return in;
}
我正在使用一个实例Vector
作为值存储Boost::program_options
:
Vector vector {0.0, 0.0, 0.0};
po::options_description opts("Usage");
opts.add_options()
("vector", po::value(&vector), "The vector");
po::variables_map vm;
po::store(po::parse_config_file("config.cfg", opts, true), vm);
po::notify(vm);
问题是如果向量值表示包含空格,则配置文件格式不起作用。例如,此配置文件正确解析:
vector = (0.0,1.1,2.2)
然而,这与空格,不解析:
vector = (0.0, 1.1, 2.2)
相反,program_options
抛出:
the argument ('(0.0, 1.1, 2.2)') for option 'vector' is invalid
但是,对于声明为 的选项std::string
,空格似乎没问题:
some_string = this is a string
我发现一些使用引号提到的帖子,但这似乎不起作用(同样的错误):
vector = "(0.0, 1.1, 2.2)"
其他一些帖子建议使用自定义解析器,但是我不确定如何实现这一点,而且处理几个空格似乎需要做很多工作。
我假设这种行为来自命令行选项的解析方式,即使这是配置文件解析。在这种情况下,像这样的命令行--vector (0.0, 1.1, 2.2)
没有多大意义(暂时忽略 shell 保留字符(
&的使用)
)
有没有好的方法来处理这个?
解决方案
不,你不能。。
编辑:经过再三考虑,我认为您可以尝试修改分隔符,如https://en.cppreference.com/w/cpp/locale/ctype
program_options
使用lexical_cast
它需要在 operator>> 之后消耗整个内容。当有空间时,内容永远不会被一个>>消耗,默认情况下,错误也是如此。
因此,您可以执行以下操作:
struct Optional {
char optional;
Optional(char optional):optional(optional){}
friend std::istream& operator>>(std::istream& is, Optional const& o) {
char next;
do{
next = is.peek();
}while(next == o.optional && is.get());
return is;
}
};
struct vector_ctype : std::ctype<wchar_t> {
bool do_is(mask m, char_type c) const {
if ((m & space) && c == L' ') {
return false; // space will NOT be classified as whitespace
}
return ctype::do_is(m, c); // leave the rest to the parent class
}
};
template<typename CharT>
std::basic_istream<CharT> &
operator>>(std::basic_istream<CharT> &in, Vector &v) {
std::locale default_locale = in.getloc();
in.imbue(std::locale(default_locale, new vector_ctype()));
in >> Expect('(') >> Optional(' ') >> v.x >> Optional(' ')
>> Expect(',') >> Optional(' ') >> v.y >> Optional(' ')
>> Expect(',') >> Optional(' ') >> v.z >> Optional(' ')
>> Expect(')');
in.imbue(default_locale);
return in;
}
int main()
{
Vector v = boost::lexical_cast<Vector>("(1, 2, 3)");
std::cout << v.x <<"," <<v.y <<"," << v.z <<std::endl;
}
输出:
1,2,3
这应该会在 program_options 中为您提供正确的输出
推荐阅读
- sql - 交易功能的完美数据库设计
- java - 有向图最短路径源到目的地 Dijkstra
- php - 我需要这个 $LoadId=implode(',',array_filter($_POST["load"])); 的输出 看起来像这样 ('7209','7210')
- windows - 脚本在windows中更改10,000个文件夹的文件夹名称
- java - 从哈希图中打印一个值到屏幕 - 一次打印多个值?
- c# - 使用 ASP.NET MVC 从列表创建下拉字段表单
- java - Android Studio:地理定位不起作用。无法在 Webview 中获取地理位置
- c# - Service Bus Queue 触发 Azure Function 的“唤醒”时间
- linux - /dev/ttyACM0:openSUSE 权限被拒绝
- android - 在 Android 中剪辑背景布局