配置文件中的多个重复节

时间:2014-04-20 04:17:57

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

我有一个配置文件格式,我希望用Boost程序选项实现(因为我之前使用过该库),但我不得不实现这样的块:

label = whatever
depth = 3

start
source = /etc
dest = /tmp/etc/
end

start
source = /usr/local/include
dest = /tmp/include
depth = 1
end

我读了in the docs我可以[sections],所以我首先想知道这个:

label = whatever
depth = 3

[dir]
source = /etc
dest = /tmp/etc/

[dir]
source = /usr/local/include
dest = /tmp/include
depth = 1

但如果我理解正确,dir将成为变量名称的一部分,因此不可能重复,这不起作用。那么我想知道将source移动到部分名称:

label = whatever
depth = 3

[/etc]
dest = /tmp/etc/

[/usr/local/include]
dest = /tmp/include
depth = 1

这似乎是一种合理的方法吗?当我不提前知道部分名称时,我想知道如何迭代部分列表?

或者,有没有更好的方法来使用程序选项库来实现这一目标?

2 个答案:

答案 0 :(得分:5)

也许您应该使用Boost property_tree而不是program_options,因为您的文件格式与Windows INI file format非常相似。提升property_tree有一个parser for INI files(以及一个序列化程序,以防您需要它)。

然后通过遍历树来实现处理您的选项。不在节中的选项将位于树根下,节选项将位于该节的节点下。

如果您愿意,可以使用program_options。关键是将true的最终参数传递给parse_config_file,即allow_unregistered_options

#include <iostream>
#include <sstream>
#include <boost/program_options.hpp>

static const std::string fileData = // sample input
   "foo=1\n"
   "[bar]\n"
   "foo=a distinct foo\n"
   "[/etc]\n"
   "baz=all\n"
   "baz=multiple\n"
   "baz=values\n"
   "a.baz=appear\n";

int main(int argc, char *argv[]) {
   namespace po = boost::program_options;

   std::istringstream is(fileData);
   po::parsed_options parsedOptions = po::parse_config_file(
      is,
      po::options_description(),
      true);                     // <== allow unregistered options

   // Print out results.
   for (const auto& option : parsedOptions.options) {
      std::cout << option.string_key << ':';

      // Option value is a vector of strings.
      for (const auto& value : option.value)
         std::cout << ' ' << value;
      std::cout << '\n';
   }

   return 0;
}

输出:

$ ./po
foo: 1
bar.foo: a distinct foo
/etc.baz: all
/etc.baz: multiple
/etc.baz: values
/etc.baz: appear

但是,请注意,您使用此方法获得的是选项向量,而不是program_options的典型用法产生的地图。因此,您最终可能会将parsed_options容器处理为可以更轻松查询的内容,并且某些内容可能看起来像property_tree

这是一个使用property_tree的类似程序。输入略有不同,因为property_tree不允许重复键。

#include <iostream>
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

static const std::string fileData = // sample input                             
   "foo=1\n"
   "[bar]\n"
   "foo=a distinct foo\n"
   "[/etc]\n"
   "foo=and another\n"
   "baz=all\n";

static void print_recursive(
   const std::string& prefix,
   const boost::property_tree::ptree& ptree) {
   for (const auto& entry : ptree) {
      const std::string& key = entry.first;
      const boost::property_tree::ptree& value = entry.second;
      if (!value.data().empty())
         std::cout << prefix + key << ": " << value.data() << '\n';
      else
         print_recursive(prefix + key + '.', value);
   }
}

int main() {
   namespace pt = boost::property_tree;

   std::istringstream is(fileData);
   pt::ptree root;
   pt::read_ini(is, root);

   print_recursive("", root);
   return 0;
}

答案 1 :(得分:0)

不了解Boost Programs Options图书馆。但INI文件格式在Win32 API中具有内置支持。

为了在不知道姓名的情况下阅读INI文件中的所有部分,您可以使用MSDN Win32 GetPrivateProfileSectionNames

要阅读部分中的所有键,您可以使用MSDN Win32 GetPrivateProfileSection

据说此API仅用于兼容性,并且在后台它可以将INI文件密钥映射到注册表。

在实践中它应该工作正常(它总是这样)。您甚至可以使用UNICODE INI文件,假设它们具有BOM标记并且您调用API的..W版本。

配置文件格式及其位置的适用性(例如,如果它可以存储在注册表中)取决于您的部署方案