【问题标题】:Boost_option to parse a configuration fileBoost_option 解析配置文件
【发布时间】:2021-08-14 22:53:54
【问题描述】:

我正在尝试解析类似于以下几行的神经网络配置文件。实际文件会有更多行,但格式相似。

Resnet50 {
    Layer CONV1 {
        Type: CONV
        Stride { X: 2, Y: 2 }       
        Dimensions { K: 64, C: 3, R: 7, S: 7, Y:224, X:224 }
    }


    Layer CONV2_1_1 {
        Type: CONV
        Stride { X: 1, Y: 1 }       
        Dimensions { K: 64, C: 64, R: 1, S: 1, Y: 56, X: 56 }
    }

我用这个Boost参数解析代码:

void to_cout(const std::vector<std::string> &v)
{
   std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>{std::cout, "\n"});
}

int main(int argc, char* argv[]) {
   namespace po = boost::program_options;
   po::options_description conf("Config file options");
   conf.add_options()("confg_file", po::value<std::string>(&file_name), "HW configuration file");
   po::options_description all_options;
   all_options.add(conf);
   po::variables_map vm;
   po::store(po::parse_command_line(argc, argv, all_options), vm);
   po::notify(vm);

   return 0;
}

似乎是一个常规的解析例程。但是配置文件没有被正确解析,因为vm的to_cout中没有输出。 parse_command_line 如何进入示例配置文件的层次结构?

【问题讨论】:

    标签: c++ parsing boost configuration-files boost-program-options


    【解决方案1】:

    这不是程序选项的意义所在。您可以使用它来读取 ini 文件,但不能使用显示的代码。您实际上是在调用parse_command_line(而不是parse_config_file)。

    您展示的代码允许您从命令行解析配置文件的名称。这也是为什么值为std::string file_name

    也许我们缺少(相当多)代码,因为在您的代码中也没有调用 to_cout,请不要介意它不适用于 vm,因为参数类型不直接匹配。我知道您可以在变量映射中循环匹配名称,这很可能是您所做的,但这并不是很相关。

    即使您确实调用 parse_config_file 也不知道如何读取该文件格式,因为文档格式是一种 INI 文件风格。

    好消息

    好消息是您的配置文件的格式确实与 Boost 属性树支持的 INFO 文件非常相似。这让我 10 年来第一次有机会实际建议使用该库:这似乎或多或少正是您所追求的:

    Live On Coliru

    #include <boost/property_tree/info_parser.hpp>
    #include <iostream>
    
    extern std::string config;
    
    int main() {
        boost::property_tree::ptree pt;
        std::istringstream iss(config);
        read_info(iss, pt);
    
        write_info(std::cout, pt);
    }
    
    std::string config = R"(
    Resnet50 {
        Layer CONV1 {
            Type: CONV
            Stride { X: 2, Y: 2 }       
            Dimensions { K: 64, C: 3, R: 7, S: 7, Y:224, X:224 }
        }
    
    
        Layer CONV2_1_1 {
            Type: CONV
            Stride { X: 1, Y: 1 }       
            Dimensions { K: 64, C: 64, R: 1, S: 1, Y: 56, X: 56 }
        }
    }
    )";
    

    打印

    Resnet50
    {
        Layer CONV1
        {
            Type: CONV
            Stride
            {
                X: 2,
                Y: 2
            }
            Dimensions
            {
                K: 64,
                C: 3,
                R: 7,
                S: 7,
                Y:224, X:224
            }
        }
        Layer CONV2_1_1
        {
            Type: CONV
            Stride
            {
                X: 1,
                Y: 1
            }
            Dimensions
            {
                K: 64,
                C: 64,
                R: 1,
                S: 1,
                Y: 56,
                X: 56
            }
        }
    }
    

    将其捆绑在一起

    您可以将它与文件名的 CLI 参数绑定在一起:

    Live On Coliru

    #include <boost/property_tree/info_parser.hpp>
    #include <boost/program_options.hpp>
    #include <iostream>
    using boost::property_tree::ptree;
    
    int main(int argc, char* argv[]) {
        std::string file_name;
        {
            namespace po = boost::program_options;
            po::options_description cliopts("options");
            cliopts.add_options() //
                ("config_file", po::value<std::string>(&file_name),
                 "HW configuration file");
    
            po::variables_map vm;
            po::store(po::parse_command_line(argc, argv, cliopts), vm);
    
            if (!vm.contains("config_file")) {
                std::cerr << cliopts << '\n';
                return 255;
            }
    
            po::notify(vm); // sets file_name
        }
    
        boost::property_tree::ptree pt;
        {
            std::ifstream ifs(file_name);
            read_info(ifs, pt);
        } // closes file
    
        for (auto const& [key, sub] : pt.get_child("Resnet50")) {
            std::cout << key << " " << sub.get_value("") << "\n";
        }
    }
    

    然后运行 ​​./test.exe --config_file config.cfg 它可能会打印例如

    Layer CONV1
    Layer CONV2_1_1
    

    ¹10 years (and more) of admonishing people 不要滥用属性树作为 XML、INI 或 JSON 解析器,因为它不是这些东西。它是……一个属性树库。

    【讨论】:

    • 谢谢。让我试试。我没有使用 to_cout ,因为执行后没有什么可以打印的。至于我为什么使用 parse_command_line 而不是 parse_config_file,这个 Boost 文档说它们是相同的:“boost::program_options::parse_config_file() 与 boost::program_options::parse_command_line() 执行相同的操作,并在boost::program_options::parsed_options 类型的对象。此对象被传递给 boost::program_options::store() 以将解析的选项存储在 vm 中。" theboostcpplibraries.com/boost.program_options.
    • 顺便问一下,pt.get_child() 可以比层次结构的第一层更深吗?那些X、Y、K等也需要解析。
    • 我不得不更改代码中的一些行以使 pt.get_child() 正常工作,例如定义“ptree children = pt.get_child("Resnet50")”。而且我不得不注释掉 vm.contains() 因为在 vm 中没有 contains() 方法。代码可以无错误地编译,但仍然无法得到预期的输出
    • 我想我需要编写另一个解析器来解码配置文件。 Boost Options 只能注册文件名。它没有触及文件内部的任何内容。解析将逐行遍历配置文件并解析每一行中的每个标记。
    • 好的,我研究了属性树示例,并将就此打开一个单独的帖子。请在那里或聊天中加入(抱歉错过了你!)
    猜你喜欢
    • 1970-01-01
    • 2021-06-16
    • 2016-03-12
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    • 2012-08-31
    • 2012-02-16
    • 1970-01-01
    相关资源
    最近更新 更多