用C++创建一个简单的配置文件和解析器

llk*_*llk 51 c++ settings configuration parsing file

我正在尝试创建一个看起来像这样的简单配置文件

url = http://mysite.com
file = main.exe
true = 0
Run Code Online (Sandbox Code Playgroud)

程序运行时,我希望它将配置设置加载到下面列出的程序变量中.

string url, file;
bool true_false;
Run Code Online (Sandbox Code Playgroud)

我做了一些研究,这个链接似乎有帮助(核子的帖子),但我似乎无法让它工作,而且我太难理解了.有一个简单的方法吗?我可以使用加载文件,ifstream但这是我自己可以得到的.谢谢!

sbi*_*sbi 50

通常,最简单的方法是分两个阶段解析这些典型的配置文件:首先读取这些行,然后逐个解析这些行.
在C++中,可以使用流从行中读取行std::getline().虽然默认情况下它会读到下一个'\n'(它会消耗,但不会返回),你也可以传递一些其他分隔符,这使它成为读取一些字符的好选择,就像=在你的例.

为简单起见,下文中假定的=用空白包围.如果要在这些位置允许空格,则必须is >> std::ws在读取值之前策略性地放置,并从键中删除尾随空格.但是,IMO在语法上增加了一点灵活性并不值得为配置文件阅读器带来麻烦.

const char config[] = "url=http://example.com\n"
                      "file=main.exe\n"
                      "true=0";

std::istringstream is_file(config);

std::string line;
while( std::getline(is_file, line) )
{
  std::istringstream is_line(line);
  std::string key;
  if( std::getline(is_line, key, '=') )
  {
    std::string value;
    if( std::getline(is_line, value) ) 
      store_line(key, value);
  }
}
Run Code Online (Sandbox Code Playgroud)

(添加错误处理留给读者练习.)


Cia*_*ale 34

正如其他人所指出的那样,使用现有的配置文件解析器库而不是重新发明轮子可能不那么重要.

例如,如果您决定使用Config4Cpp库(我维护),那么您的配置文件语法将略有不同(在值周围加上双引号并使用分号终止赋值语句),如下例所示:

# File: someFile.cfg
url = "http://mysite.com";
file = "main.exe";
true_false = "true";
Run Code Online (Sandbox Code Playgroud)

以下程序解析上述配置文件,将所需的值复制到变量中并打印出来:

#include <config4cpp/Configuration.h>
#include <iostream>
using namespace config4cpp;
using namespace std;

int main(int argc, char ** argv)
{
    Configuration *  cfg = Configuration::create();
    const char *     scope = "";
    const char *     configFile = "someFile.cfg";
    const char *     url;
    const char *     file;
    bool             true_false;

    try {
        cfg->parse(configFile);
        url        = cfg->lookupString(scope, "url");
        file       = cfg->lookupString(scope, "file");
        true_false = cfg->lookupBoolean(scope, "true_false");
    } catch(const ConfigurationException & ex) {
        cerr << ex.c_str() << endl;
        cfg->destroy();
        return 1;
    }
    cout << "url=" << url << "; file=" << file
         << "; true_false=" << true_false
         << endl;
    cfg->destroy();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Config4Cpp 网站提供了全面的文档,但只阅读"入门指南"的第2章和第3章应该足以满足您的需求.

  • "据我所知,Config4*是迄今为止世界上最好的配置文件解析器.相比之下,竞争技术(如XML,JSON,Java属性,Windows注册表等)是平庸和简单的." - 由于您网站上的这个自命不凡的声明,没有下载. (19认同)
  • 当然希望你的config4star有一个公共git repo所以我可以在另一个带链接的项目中使用它而不是包含实际的代码... (9认同)

Ker*_* SB 13

一个天真的方法可能如下所示:

#include <map>
#include <sstream>
#include <stdexcept>
#include <string>

std::map<std::string, std::string> options; // global?

void parse(std::istream & cfgfile)
{
    for (std::string line; std::getline(cfgfile, line); )
    {
        std::istringstream iss(line);
        std::string id, eq, val;

        bool error = false;

        if (!(iss >> id))
        {
            error = true;
        }
        else if (id[0] == '#')
        {
            continue;
        }
        else if (!(iss >> eq >> val >> std::ws) || eq != "=" || iss.get() != EOF)
        {
            error = true;
        }

        if (error)
        {
            // do something appropriate: throw, skip, warn, etc.
        }
        else
        {
            options[id] = val;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以从options程序中的任何位置访问全局地图中的每个选项值.如果您想要可转换性,可以将映射类型设为a boost::variant.

  • @sop:是的,这是非常可怕的代码.我做了一些改进.[演示](http://ideone.com/evTjHO) (3认同)

小智 13

libconfig非常简单,而且更好的是,它使用伪json表示法来提高可读性.

易于在Ubuntu上安装: sudo apt-get install libconfig++8-dev

和链接: -lconfig++

  • 该链接指向一个旧分支。libconfig 站点位于:https://hyperrealm.github.io/libconfig/ 存储库位于:https://github.com/hyperrealm/libconfig (3认同)

pat*_*ato 6

如何将您的配置格式化为 JSON,并使用像jsoncpp这样的库?

例如

{"url": "http://mysite dot com",
"file": "main.exe",
"true": 0}
Run Code Online (Sandbox Code Playgroud)

然后您可以将其读入命名变量,甚至将其全部存储在 std::map 等中。后者意味着您可以添加选项而无需更改和重新编译您的配置解析器。