解析与序列容器的命令行选项? [英] parsing command-line options with sequence containers?
问题描述
此问题已经来临之前,但似乎没有一个答案提供提振替代品
式的泛型编程。
This question has come up before, but it seems that none of the answers provide alternatives with boost
-style generic programming.
许多人一样我使用boost:program_options解析命令行行选项。我现在的项目是操纵与运营商,其顺序是不能互换的数据(例如图像)的程序,的例如的
Like many I use boost:program_options to parse command line line options. My current project is a program to manipulate data (e.g. images) with operators whose order is not interchangeable, e.g.
的然后用2 的结果加3乘 $操作-in someimage.tif -a 3 -m 2
通常不是相同
的乘以2,然后加3 的结果 $操作-in someimage.tif -m 2 -a 3
的 -in
选项加载文件内容到一个vector current_image
,并在命令行上修改每个选项 current_image
。
The -in
option loads the file contents into a vector current_image
, and each option on the command line modifies current_image
.
但 variable_map
容器不保留在其中添加选项的顺序。未明确,至少。在这个帖子最接近于我有什么想法,但后来的额外的解析code需要是差不多的与 getopt的()
。
But the variable_map
container does not retain the order in which options are added. Not explicitly, at least. The answer in this post comes closest to what I have in mind, but then the amount of extra parsing code needed is about the same as with getopt()
.
有谁知道一种方法来存储在升压提供的容器程序选项的顺序?它是根本不可能的?或者是有可能(甚至实现)带有序列容器?
Does anyone know a way to store the order of program options in the boost-provided container? Is it fundamentally impossible? Or is it possible (maybe even implemented) with a sequence container?
的编辑1 的我也觉得这的真的老帖子这似乎仍然是有效的,说明是你可以遍历variables_map。当然,为了实际上没有指定是相同的命令行(留给编译器作者)的顺序,所以我想它仍然归类为一个黑客。结果
的编辑2 的,作为选项是由选项字符串进行排序,以便迭代顺序是不一样的插入顺序是不够的。
EDIT 1 I did find this really old post which seems still valid, stating that yes you can just iterate over a variables_map. Of course the order is not actually specified to be the same as the order on the command line (left to the compiler writers), so I guess it does still classify as a hack.
EDIT 2 That is not enough as the options are sorted by option string so the iteration order is not the same as the insertion order.
推荐答案
其实你有什么有更类似于一个前pression语法。我建议写,而不是使用这个program_options(AB?)语法/分析器。
Actually what you have there is more akin to an expression grammar. I'd suggest writing a grammar/parser for that instead of (ab?)using program_options for this.
-
如果你的程序需要选择:使用程序选项
If your program takes options: use program options.
如果你的程序需要一个前pression:使用前pression解析器
If your program takes an expression: use an expression parser.
一个例子:
<大骨节病> 住在Coliru 骨节病>
// #define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct Operation {
enum Kind { add, multiply } kind;
double operand;
friend std::ostream& operator<<(std::ostream& os, Kind k) {
switch (k) {
case add: return os << "--add";
case multiply: return os << "--multiply";
};
return os << "??";
}
};
BOOST_FUSION_ADAPT_STRUCT(Operation, (Operation::Kind,kind)(double,operand))
template <typename It, typename Skipper = qi::blank_type>
struct expression_grammar : qi::grammar<It, std::vector<Operation>(), Skipper> {
expression_grammar() : expression_grammar::base_type(start) {
using namespace qi;
opkinds.add
("-a", Operation::add)
("--add", Operation::add)
("-m", Operation::multiply)
("--multiply", Operation::multiply)
;
option = opkinds > eol > double_;
start = *(option > eol);
BOOST_SPIRIT_DEBUG_NODES((start)(option))
}
private:
qi::symbols<char, Operation::Kind> opkinds;
qi::rule<It, Operation(), Skipper> option;
qi::rule<It, std::vector<Operation>(), Skipper> start;
};
int main(int argc, char const** argv) {
std::stringstream iss;
if (argc)
std::copy(argv+1, argv+argc, std::ostream_iterator<const char*>(iss, "\n"));
typedef boost::spirit::istream_iterator It;
expression_grammar<It> grammar;
It first(iss >> std::noskipws), last;
std::vector<Operation> operations;
bool ok = qi::phrase_parse(first, last, grammar, qi::blank, operations);
if (ok)
{
std::cout << "Parse success\n";
for (auto const& op : operations)
std::cout << boost::fusion::as_vector(op) << "\n";
} else
std::cout << "Parse failed\n";
if (first!=last)
std::cout << "Remaining input: '" << std::string(first,last) << "'\n";
}
请注意
- 我选择,无偿,用
EOL
作为选项分隔符。您可能需要使用'\\ 0'
来代替。这是最简单的,因为空白
队长已经跳过空白/除/EOL
。我懒惰:) -
您可能wnat混合和匹配(而不是把所有的参数作为前pression的一部分)。一个常见的模式是
- I choose, gratuitously, to use
eol
as the option separator. You might want to use'\0'
instead. This was easiest because theblank
skipper already skips whitespace /except/eol
. I'm lazy :) You might wnat to mix-and-match (not treat all parameters as part of the expression). A common pattern would be
myprogram -x option1 -v -o filename -- my expression grammar follows
一个常见的替代模式是使前pression一个参数:
A common alternative pattern is to make the expression a single parameter:
myprogram -e 'add 5; multiply 32;' -x option1
请参阅这种方法的 住在Coliru 太
See this approach Live on Coliru too
我是用解析成功重新打印懒惰(我不想实施运营商的LT;&LT;
为操作
键入)
I was lazy again with the "Parse success" printing (I didn't want to implement operator<<
for the Operation
type)
启用的#define BOOST_SPIRIT_DEBUG
调试信息(注释的第一行)
enable debug info with #define BOOST_SPIRIT_DEBUG
(uncomment the first line)
<start>
<try>-a\n8\n-m\n7\n-a\n32\n</try>
<option>
<try>-a\n8\n-m\n7\n-a\n32\n</try>
<success>\n-m\n7\n-a\n32\n</success>
<attributes>[[--add, 8]]</attributes>
</option>
<option>
<try>-m\n7\n-a\n32\n</try>
<success>\n-a\n32\n</success>
<attributes>[[--multiply, 7]]</attributes>
</option>
<option>
<try>-a\n32\n</try>
<success>\n</success>
<attributes>[[--add, 32]]</attributes>
</option>
<option>
<try></try>
<fail/>
</option>
<success></success>
<attributes>[[[--add, 8], [--multiply, 7], [--add, 32]]]</attributes>
</start>
Parse success
(--add 8)
(--multiply 7)
(--add 32)
这篇关于解析与序列容器的命令行选项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!