代码之家  ›  专栏  ›  技术社区  ›  Louis Marascio

可以增强程序选项分隔逗号分隔的参数值

  •  3
  • Louis Marascio  · 技术社区  · 14 年前

    如果我的命令行是:

    > prog --mylist=a,b,c
    

    是否可以设置Boost的程序选项以查看 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
    

    有没有方法配置程序选项以便它看到 A、B、C 作为三个值,每个值都应该插入向量,而不是一个?

    我使用Boost 1.41,G+4.5.0 20100520,并启用了C++0X实验扩展。

    编辑:

    接受的解决方案可以工作,但最终变得更复杂,IMO,而不仅仅是迭代向量并手动拆分值。最后,我接受了詹姆斯·麦克内利斯的建议,并以这种方式实施了它。不过,他的解决方案并没有作为答案提交,所以我接受了香港国际机场另一个正确的解决方案。两者都有效,但手动标记化技术更清晰。

    3 回复  |  直到 11 年前
        1
  •  3
  •   hkaiser    14 年前

    您可以为您的选项注册自定义验证器:

    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
    }
    
        2
  •  2
  •   Jacob    14 年前

    我自己没有尝试过这样做,但您可能可以使用与随附的custom_syntax.cpp示例中相同的方法。 program_options ,编写自己的解析器,作为额外的解析器提供。有一些信息 here 举个简短的例子。然后,您可以将其与james关于使用boost::tokenizer的建议结合起来,或者按照他的建议进行操作。

        3
  •  2
  •   malat    11 年前

    以下是我现在使用的:

    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;
    }