2010-06-17 38 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; 
}