解析与序列容器的命令行选项? [英] parsing command-line options with sequence containers?

查看:126
本文介绍了解析与序列容器的命令行选项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题已经来临之前,但似乎没有一个答案提供提振替代品式的泛型编程。

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 the blank 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆