【问题标题】:Use Boost Program Options to parse an arbitrary string使用 Boost Program Options 解析任意字符串
【发布时间】:2013-08-22 11:11:06
【问题描述】:

我想在我的程序中实现一个类似命令行的界面。所以我收到了遵循正常命令行语法的字符串(例如“-G foo -dp bar --help”)。由于我不想再次实现解析器,我想使用 Boost。

问题是:如何将字符串传递给 Boost 程序选项,而不是 argCount 和 argValues 的组合。我是否需要先将文本转换为数字 (argCount) 和 char* 数组 (argValues) 才能做到这一点?如果是的话......有没有简单的方法可以做到这一点?

提前致谢。

【问题讨论】:

  • 为什么要传递一个字符串?您已经在您的 c++ 程序中获得了 char** 的选项?
  • 我使用 UNIX 套接字 (asio::local) 来传递 std::string。现在我想通过使用程序选项来解析这个字符串。问题是示例只包含 po::parse_command_line(ac, av, desc),但我没有 av。我有一个包含参数的完整字符串。
  • @codeling 因为我在写单元测试。

标签: c++ boost boost-program-options


【解决方案1】:

一种方法是将std::string 标记为std::vector<std::string>,然后将结果传递给Boost.ProgramOption 的command_line_parser。 Boost.ProgramOption 的documentation 简要介绍了这种方法。此外,我在this 的部分答案中使用了类似的方法。

这是一个最小的完整示例:

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

产生以下输出:

address = 127.0.0.1
port = 12345

【讨论】:

  • linux下我们不需要自己tokenize,使用boost split_unix。
  • 关于 split_unix 的评论应该完全是一个答案。接受的答案也是一个很好的答案,但是 split_unix 可以工作,除非您真的需要自定义标记化,并且已经构建。也适用于窗户。我会添加它作为答案。
【解决方案2】:

boost::program_options 有一个名为split_unix 的函数,正如@FaceBro 指出的那样。它也适用于 Windows,因此以下是跨平台的,借用了已接受答案的主要示例结构:

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(po::split_unix(input))
                .options(desc).run(), vm);
  po::notify(vm);

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

【讨论】:

    猜你喜欢
    • 2021-07-10
    • 1970-01-01
    • 2012-07-30
    • 2013-11-12
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多