2013-08-22 47 views
5

Tôi muốn triển khai một giao diện dòng lệnh giống như bên trong chương trình của mình. Vì vậy, tôi nhận được các chuỗi theo cú pháp dòng lệnh thông thường (ví dụ: "-G foo -dp bar --help"). Vì tôi không muốn thực hiện lại trình phân tích cú pháp, tôi muốn sử dụng Boost.Sử dụng Tùy chọn chương trình tăng cường để phân tích cú pháp một chuỗi tùy ý

Câu hỏi đặt ra là: Làm cách nào tôi có thể chuyển một chuỗi để Tăng tùy chọn chương trình thay vì kết hợp giữa argCount và argValues. Tôi có cần phải biến đổi văn bản thành một số (argCount) và một mảng char * (argValues) để làm điều đó không? Và nếu có ... có cách nào dễ dàng để làm điều này không?

Xin cảm ơn trước.

+0

lý do tại sao bạn sẽ vượt qua một chuỗi? bạn nhận được các tùy chọn như char ** đã có trong chương trình C++ của bạn? – codeling

+0

Tôi sử dụng ổ cắm UNIX (asio :: local) để truyền xung quanh chuỗi std ::. Bây giờ tôi muốn phân tích chuỗi này bằng cách sử dụng các tùy chọn chương trình. Vấn đề là ví dụ chỉ bao gồm po :: parse_command_line (ac, av, desc), nhưng tôi không có av. Tôi có một chuỗi hoàn chỉnh chứa các đối số. – Darneas

+0

@codeling Vì tôi đang viết một bài kiểm tra đơn vị. – Eyal

Trả lời

7

Một cách tiếp cận là mã hóa std::string thành một std::vector<std::string>, sau đó chuyển kết quả đến Boost.ProgramOption's command_line_parser. Số documentation của Boost.ProgramOption sẽ trình bày ngắn gọn cách tiếp cận này. Ngoài ra, tôi sử dụng cách tiếp cận tương tự như một phần của câu trả lời this.

Đây là một hoàn dụ tối thiểu:

#include <algorithm> 
#include <iostream> 
#include <iterator> 
#include <string> 
#include <vector> 

#include <boost/bind.hpp> 
#include <boost/program_options.hpp> 
#include <boost/tokenizer.hpp> 

// copy_if was left out of the C++03 standard, so mimic the C++11 
// behavior to support all predicate types. The alternative is to 
// use remove_copy_if, but it only works for adaptable functors. 
template <typename InputIterator, 
      typename OutputIterator, 
      typename Predicate> 
OutputIterator 
copy_if(InputIterator first, 
     InputIterator last, 
     OutputIterator result, 
     Predicate pred) 
{ 
    while(first != last) 
    { 
    if(pred(*first)) 
     *result++ = *first; 
    ++first; 
    } 
    return result; 
} 

/// @brief Tokenize a string. The tokens will be separated by each non-quoted 
///  space or equal character. Empty tokens are removed. 
/// 
/// @param input The string to tokenize. 
/// 
/// @return Vector of tokens. 
std::vector<std::string> tokenize(const std::string& input) 
{ 
    typedef boost::escaped_list_separator<char> separator_type; 
    separator_type separator("\\", // The escape characters. 
          "= ", // The separator characters. 
          "\"\'"); // The quote characters. 

    // Tokenize the intput. 
    boost::tokenizer<separator_type> tokens(input, separator); 

    // Copy non-empty tokens from the tokenizer into the result. 
    std::vector<std::string> result; 
    copy_if(tokens.begin(), tokens.end(), std::back_inserter(result), 
      !boost::bind(&std::string::empty, _1)); 
    return result; 
} 

int main() 
{ 
    // Variables that will store parsed values. 
    std::string address; 
    unsigned int port;  

    // Setup options. 
    namespace po = boost::program_options; 
    po::options_description desc("Options"); 
    desc.add_options() 
    ("address", po::value<std::string>(&address)) 
    ("port", po::value<unsigned int>(&port)) 
    ; 

    // Mock up input. 
    std::string input = "--address 127.0.0.1 --port 12345"; 

    // Parse mocked up input. 
    po::variables_map vm; 
    po::store(po::command_line_parser(tokenize(input)) 
       .options(desc).run(), vm); 
    po::notify(vm); 

    // Output. 
    std::cout << "address = " << address << "\n" 
       "port = " << port << std::endl; 
} 

nào xuất ra như sau:

address = 127.0.0.1 
port = 12345 
+0

Chúng tôi không cần mã thông báo của riêng mình dưới Linux, hãy sử dụng tăng split_unix. – FaceBro