2010-06-17 76 views
2

如果我的命令行是:可能促进Program_options单独的逗号分隔的参数值

> prog --mylist=a,b,c 

可能促进的program_options被设置看到三个不同的参数值的mylist说法?我已经配置program_options为:当我检查mylist参数的值

namespace po = boost::program_options; 
po::options_description opts("blah") 

opts.add_options() 
    ("mylist", std::vector<std::string>>()->multitoken, "description"); 

po::variables_map vm; 
po::store(po::parse_command_line(argc, argv, opts), vm); 
po::notify(vm); 

,我看到一个值作为a,b,c。我希望看到三个不同的值,以逗号分隔。如果我在命令行指定为这工作得很好:

> prog --mylist=a b c 

> prog --mylist=a --mylist=b --mylist=c 

是否有配置program_options因此,它认为应该分别被插入载体a,b,c三个值的方法,而不是一个?

我使用boost 1.41,g ++ 4.5.0 20100520,并启用了C++ 0x实验扩展。

编辑:

接受的解决方案工作,但最终被更加复杂,IMO,不仅仅是通过矢量迭代并手动分裂值。最后,我接受了詹姆斯麦克奈利斯的建议并以此方式实施。然而,他的解决方案并未作为答案提交,所以我接受了hkaiser的另一个正确解决方案。两者都有效,但手动标记化更清晰。

+1

如果没有别的,可以使用'boost :: tokenizer'来标记逗号分隔值。 – 2010-06-17 19:53:00

+0

这可能是最容易做的事情。只需后处理参数并处理逗号出现的情况。 – 2010-06-17 20:31:31

回答

2

你可以任你选择注册一个自定义的验证:

namespace po = boost::program_options; 

struct mylist_option 
{ 
    // values specified with --mylist will be stored here 
    vector<std::string> values; 

    // Function which validates additional tokens from command line. 
    static void 
    validate(boost::any &v, std::vector<std::string> const &tokens) 
    { 
     if (v.empty()) 
      v = boost::any(mylist_option()); 

     mylist_option *p = boost::any_cast<mylist_option>(&v); 
     BOOST_ASSERT(p); 

     boost::char_separator<char> sep(","); 
     BOOST_FOREACH(std::string const& t, tokens) 
     { 
      if (t.find(",")) { 
       // tokenize values and push them back onto p->values 
       boost::tokenizer<boost::char_separator<char> > tok(t, sep); 
       std::copy(tok.begin(), tok.end(), 
        std::back_inserter(p->values)); 
      } 
      else { 
       // store value as is 
       p->values.push_back(t); 
      } 
     } 
    } 
}; 

然后可以用作:

opts.add_options()     
    ("mylist", po::value<mylist_option>()->multitoken(), "description"); 

和:

if (vm.count("mylist")) 
{ 
    // vm["mylist"].as<mylist_option>().values will hold the value specified 
    // using --mylist 
} 
+0

这工作,有一些修改。我不得不从结构中提取验证函数并根据文档重载它。我讨厌创造一种人造型来做我想做的事,但那就是生活。最后,我只是遍历矢量并将值简化为一个简单的循环。它比自定义验证器少了约50%的代码。不过,我接受这个答案,因为它是有效的,并且是唯一正确答案。 – 2010-06-19 23:57:46

+1

由于某种原因,此代码不能编译我了(提升1.55) – malat 2014-02-06 15:32:45

+0

我解决了它:http://stackoverflow.com/questions/26389297/how-to-parse-comma-separated-values-with-boostprogram -options – 4ntoine 2014-10-16 07:20:56

2

我还没有尝试过这样做,但是您可能可以使用与program_options提供的custom_syntax.cpp示例中相同的方法来编写您自己的解析器,该解析器可以作为额外的解析器提供。有一个简短的例子here。然后你可以将它与James使用boost :: tokenizer的建议结合起来,或者按照他的建议。

+0

我认为这不会起作用。它似乎只调用解析器的参数,而不是它们的值。 – 2010-06-17 20:30:58

+0

我回过头来,它会为每个标记调用它,而不是每个参数。会再试验一些。 – 2010-06-17 20:37:59

+0

@lrm:对不起,我无法提供更多的帮助,还没有使用过很多的program_options,但让我们知道它如何去决定如何去做,而不仅仅是简单地标记字符串。 – Jacob 2010-06-17 20:45:27

2

这里是我使用的是什么现在:

template<typename T, int N> class mytype; 
template<typename T, int N> std::istream& operator>> (std::istream& is, mytype<T,N>& rhs); 
template<typename T, int N> std::ostream& operator<< (std::ostream& os, const mytype<T,N>& rhs); 
template < typename T, int N > 
struct mytype 
{ 
    T values[N]; 
    friend std::istream& operator>> <>(std::istream &is, mytype<T,N> &val); 
    friend std::ostream& operator<< <>(std::ostream &os, const mytype<T,N> &val); 
}; 
template<typename T, int N> 
inline std::istream& operator>>(std::istream &is, mytype<T,N> &val) 
{ 
    for(int i = 0; i < N; ++i) 
    { 
    if(i) 
     if (is.peek() == ',') 
     is.ignore(); 
    is >> val.values[i]; 
    } 
    return is; 
} 
template<typename T, int N> 
inline std::ostream& operator<<(std::ostream &os, const mytype<T,N> &val) 
{ 
    for(int i = 0; i < N; ++i) 
    { 
    if(i) os << ','; 
    os << val.values[i]; 
    } 
    return os; 
} 

int main(int argc, char *argv[]) 
{ 
    namespace po = boost::program_options; 

    typedef mytype<int,2> mytype; // let's test with 2 int 
    mytype my; 
    try 
    { 
    po::options_description desc("the desc"); 
    desc.add_options() 
     ("mylist", po::value<mytype>(&my), "mylist desc") 
     ; 

    po::variables_map vm; 
    po::store(po::command_line_parser(argc, argv).options(desc).run(), vm); 
    po::notify(vm); 

    if (vm.count("mylist")) 
     { 
     const mytype ret = vm["mylist"].as<mytype >(); 
     std::cerr << "mylist: " << ret << " or: " << my << std::endl; 
     } 
    } 
    catch(std::exception& e) 
    { 
    std::cout << e.what() << "\n"; 
    }  
    return 0; 
}