2010-06-17 2 views
2

Если моя командная строка:может повысить Program_options отдельные разделенные запятой аргумент значения

> prog --mylist=a,b,c 

Можно увеличить program_options-х быть настроен, чтобы увидеть три различных значения аргументов для mylist аргумента? Я настроил program_options как:

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

Когда я проверяю значение mylist аргумента, я вижу одно значение как 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.

EDIT:

Принятые работы решения, но заканчивает тем более сложным, IMO, чем просто перебор вектора и разделив значения вручную. В конце концов, я принял предложение от Джеймса Макнеллиса и реализовал его таким образом. Однако его решение не было представлено в качестве ответа, поэтому я принял другое правильное решение от hkaiser. Оба работали, но ручная токенизация понятна.

+1

Если ничего другого, вы можете использовать 'boost :: tokenizer', чтобы токенизировать значения, разделенные запятыми. –

+0

Это, наверное, самая простая вещь. Просто отправьте аргумент и обработайте случай, когда появляется запятая. –

ответ

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

Это сработало, с некоторыми изменениями. Мне пришлось извлечь функцию проверки из структуры и перегрузить ее в соответствии с документацией.Мне не нравится создавать искусственный тип, чтобы делать то, что я хочу, но это жизнь. В конце концов, я просто повторил вектор и обозначил значения w/простой цикл. Его код на 50% меньше, чем пользовательский валидатор. Тем не менее, я принимаю этот ответ, поскольку он работает, и это единственный правильный ответ. –

+1

по какой-то причине этот код для меня не компилируется (boost 1.55) – malat

+0

Я решил: http://stackoverflow.com/questions/26389297/how-to-parse-comma-separated-values-with-boostprogram -опции – 4ntoine

2

Я не пробовал делать это сам, но вы могли бы использовать тот же подход, что и в примере custom_syntax.cpp, который снабжен program_options, чтобы написать собственный анализатор, который вы можете предоставить в качестве дополнительного парсера. Немного информации here с кратким примером. Тогда вы можете либо объединить это с предложением Джеймса использовать boost :: tokenizer, либо просто следовать его предложению.

+0

Я не думаю, что это сработает. По-видимому, он вызывает только парсер для аргументов, а не их значений. –

+0

Я беру это обратно, он называет его для каждого токена, а не для каждого аргумента. Будем экспериментировать еще. –

+0

@lrm: Извините, я не могу больше помогать, много не использовал program_options, но дайте нам знать, как это происходит, если вы решите пойти с этим, а не просто символизировать строку. – Jacob

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; 
} 
Смежные вопросы