首页 > 解决方案 > 将空字符串引号(例如“”)作为值传递给未注册的 boost::program_options

问题描述

概括

我见过这个问题,它询问并回答了如何为定义的值传递无操作。但是,如何从命令行将空字符串传递给对象,尤其是对于未注册的选项?以及如何避免由于传入空字符串/值而导致提升分段错误?

细节

例如,我有如下所示的选项。它们被程序的主入口点视为未注册。然后将它们传递给另一个库进行解析。

# These are equivalent, with and without quotes
--MyLibrary.myCsv="one,two,three"
--MyLibrary.myCsv=one,two,three

但是,此选项可以为空,例如:

--MyLibrary.myCsv=""

现在,由于 shell 删除了引号,这会引发 SegFault(至少对于 boost 1.67 之前的版本)。明确地说,我得到一个异常,然后是 SegFault 消息“中止(核心转储)”:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::program_options::invalid_command_line_syntax> >'
  what():  the argument for option '--MyLibrary.myCsv' should follow immediately after the equal sign
(core dumped)

我可以这样写:

--MyLibrary.myCsv=\"\"

它不会出现段错误,但幽默的是,它将设置为"\"\"",这显然不是一个空字符串......有没有办法只给它一个空字符串作为值?

示例代码

这是一个展示我的问题的小例子(希望如此)。我叫它emptyQuotes.cpp

#include <iostream>
#include <vector>
#include <string>
#include <boost/program_options.hpp>

using namespace std;
namespace po = boost::program_options;

/**
 * @brief parser for another (potentially external) library.
 * 
 * For simplicity, it looks for '=' to split key from value
 */
void libraryParser( const vector<string>& options )
{
    for ( auto it = options.begin(); it != options.end(); ++it )
    {
        size_t eqPos = it->find('=');
        size_t start = it->find_first_not_of('-');

        string key = it->substr(start, eqPos-start);
        string val = it->substr(eqPos + 1);

        cout << "    key = \"" << key << "\"; val = \"" << val << "\"\n";
        cout << "    Is val empty? ";
        if(val.empty())
            cout << "yes";
        else
            cout << "no"; 
        cout << "\n";
    }
}

int main (int argc, char** argv)
{
    cout << "Command line:\n  ";
    for ( int ii = 0; ii < argc; ++ii )
        cout << argv[ii] << " ";
    cout << "\n";

    // Commands that the basic entry point would know
    boost::program_options::options_description basic("Basic");
    basic.add_options()
        ( "help,h", "produce a help message" );


    po::parsed_options parsed = po::command_line_parser(argc, argv)
        .options(basic)
        .allow_unregistered() // <-I don't know how to handle blank values here
        .run();

    po::variables_map vm;
    po::store(parsed, vm);
    vector<string> unregOptions = po::collect_unrecognized( parsed.options, po::exclude_positional );

    libraryParser(unregOptions);

    cout << "\n";
    return 0;
}

运行以下得到SegFault

./emptyQuotes --MyLibrary.myVal=""
Command line:
  ./emptyQuotes --MyLibrary.myVal= 
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::program_options::invalid_command_line_syntax> >'
  what():  the argument for option '--MyLibrary.myVal' should follow immediately after the equal sign
Aborted (core dumped)

它报告斜杠的值不为空:

./emptyQuotes --MyLibrary.myVal=\"\"
Command line:
  ./emptyQuotes --MyLibrary.myVal="" 
    key = "MyLibrary.myVal"; val = """"
    Is val empty? no

标签: c++boostboost-program-options

解决方案


推荐阅读