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

发布于 2024-11-27 03:25:52 字数 417 浏览 1 评论 0原文

我正在尝试创建一个简单的配置文件,

url = http://mysite.com
file = main.exe
true = 0

在程序运行时看起来像这样,我希望它将配置设置加载到下面列出的程序变量中。

string url, file;
bool true_false;

我做了一些研究,这个链接似乎有帮助(nucleon的帖子)但我似乎无法让它发挥作用,而且它太复杂了,我无法理解。有一个简单的方法可以做到这一点吗?我可以使用 ifstream 加载文件,但这只是我自己所能做到的。谢谢!

I am trying to create a simple configuration file that looks like this

url = http://mysite.com
file = main.exe
true = 0

when the program runs, I would like it to load the configuration settings into the programs variables listed below.

string url, file;
bool true_false;

I have done some research and this link seemed to help (nucleon's post) but I can't seem to get it to work and it is too complicated to understand on my part. Is there a simple way of doing this? I can load the file using ifstream but that is as far as I can get on my own. Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

我不在是我 2024-12-04 03:25:53

这是配置文件中“=”符号和数据之间的空格的简单解决方法。从“=”号后面的位置分配给 istringstream,并且在从中读取时,任何前导空格都会被忽略。

注意:在循环中使用 istringstream 时,请确保在为其分配新字符串之前调用clear()。

//config.txt
//Input name = image1.png
//Num. of rows = 100
//Num. of cols = 150

std::string ipName;
int nR, nC;

std::ifstream fin("config.txt");
std::string line;
std::istringstream sin;

while (std::getline(fin, line)) {
 sin.str(line.substr(line.find("=")+1));
 if (line.find("Input name") != std::string::npos) {
  std::cout<<"Input name "<<sin.str()<<std::endl;
  sin >> ipName;
 }
 else if (line.find("Num. of rows") != std::string::npos) {
  sin >> nR;
 }
 else if (line.find("Num. of cols") != std::string::npos) {
  sin >> nC;
 }
 sin.clear();
}

Here is a simple work around for white space between the '=' sign and the data, in the config file. Assign to the istringstream from the location after the '=' sign and when reading from it, any leading white space is ignored.

Note: while using an istringstream in a loop, make sure you call clear() before assigning a new string to it.

//config.txt
//Input name = image1.png
//Num. of rows = 100
//Num. of cols = 150

std::string ipName;
int nR, nC;

std::ifstream fin("config.txt");
std::string line;
std::istringstream sin;

while (std::getline(fin, line)) {
 sin.str(line.substr(line.find("=")+1));
 if (line.find("Input name") != std::string::npos) {
  std::cout<<"Input name "<<sin.str()<<std::endl;
  sin >> ipName;
 }
 else if (line.find("Num. of rows") != std::string::npos) {
  sin >> nR;
 }
 else if (line.find("Num. of cols") != std::string::npos) {
  sin >> nC;
 }
 sin.clear();
}
殤城〤 2024-12-04 03:25:53

我想推荐一个单头 C++ 11 YAML解析器mini-yaml。

取自上述存储库的快速入门示例。

file.txt

key: foo bar
list:
  - hello world
  - integer: 123
    boolean: true

.cpp

Yaml::Node root;
Yaml::Parse(root, "file.txt");

// Print all scalars.
std::cout << root["key"].As<std::string>() << std::endl;
std::cout << root["list"][0].As<std::string>() << std::endl;
std::cout << root["list"][1]["integer"].As<int>() << std::endl;
std::cout << root["list"][1]["boolean"].As<bool>() << std::endl;

// Iterate second sequence item.
Node & item = root[1];
for(auto it = item.Begin(); it != item.End(); it++)
{
    std::cout << (*it).first << ": " << (*it).second.As<string>() << std::endl;
}

输出

foo bar
hello world
123
1
integer: 123
boolean: true

I would like to recommend a single header C++ 11 YAML parser mini-yaml.

A quick-start example taken from the above repository.

file.txt

key: foo bar
list:
  - hello world
  - integer: 123
    boolean: true

.cpp

Yaml::Node root;
Yaml::Parse(root, "file.txt");

// Print all scalars.
std::cout << root["key"].As<std::string>() << std::endl;
std::cout << root["list"][0].As<std::string>() << std::endl;
std::cout << root["list"][1]["integer"].As<int>() << std::endl;
std::cout << root["list"][1]["boolean"].As<bool>() << std::endl;

// Iterate second sequence item.
Node & item = root[1];
for(auto it = item.Begin(); it != item.End(); it++)
{
    std::cout << (*it).first << ": " << (*it).second.As<string>() << std::endl;
}

Output

foo bar
hello world
123
1
integer: 123
boolean: true
2024-12-04 03:25:53

没有人提到。我更喜欢它们,因为它们非常易于阅读并且不易出错。微量元素:

#include <fstream>
#include <iostream>
#include <regex>
#include <string>

struct config_t
{
    // (define variables here)

    void read_from(const std::string& fname)
    {
        std::ifstream cfg_file(fname);
        if(!cfg_file.good())
            throw std::runtime_error("Cannot open file: " + fname);

        std::string line;
        while(std::getline(cfg_file, line))
        {
            std::regex re(R"XXX(^(\s*(\S+)\s*=\s*(\S+))?\s*(#.*)?$)XXX",
                std::regex::optimize);
            std::smatch match;
            if(std::regex_search(line, match, re))
            {
                if(match.length(2))
                {
                    std::string key = match.str(2),
                        value = match.str(3);
                    std::cout << "key-value-pair: " << key << " -> " << value << std::endl;
                    // (fill variables here)
                }
            }
            else
                throw std::runtime_error("Invalid line: " + line);
        }
    }
};

int main(int argc, char** argv)
{
    int rval = EXIT_SUCCESS;
    try
    {
        config_t cfg;
        if (argc != 2)
            throw std::runtime_error("Expecting exactly one argument");
        cfg.read_from(argv[1]);
    }
    catch (const std::exception& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        rval = EXIT_FAILURE;
    }
    return rval;
}

No one mentioned <regex>. I prefer them since they are really easy to read and less error prone. MWE:

#include <fstream>
#include <iostream>
#include <regex>
#include <string>

struct config_t
{
    // (define variables here)

    void read_from(const std::string& fname)
    {
        std::ifstream cfg_file(fname);
        if(!cfg_file.good())
            throw std::runtime_error("Cannot open file: " + fname);

        std::string line;
        while(std::getline(cfg_file, line))
        {
            std::regex re(R"XXX(^(\s*(\S+)\s*=\s*(\S+))?\s*(#.*)?$)XXX",
                std::regex::optimize);
            std::smatch match;
            if(std::regex_search(line, match, re))
            {
                if(match.length(2))
                {
                    std::string key = match.str(2),
                        value = match.str(3);
                    std::cout << "key-value-pair: " << key << " -> " << value << std::endl;
                    // (fill variables here)
                }
            }
            else
                throw std::runtime_error("Invalid line: " + line);
        }
    }
};

int main(int argc, char** argv)
{
    int rval = EXIT_SUCCESS;
    try
    {
        config_t cfg;
        if (argc != 2)
            throw std::runtime_error("Expecting exactly one argument");
        cfg.read_from(argv[1]);
    }
    catch (const std::exception& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        rval = EXIT_FAILURE;
    }
    return rval;
}
ぽ尐不点ル 2024-12-04 03:25:53

SimpleConfigFile 是一个库,它完全可以满足您的需求,并且使用起来非常简单。

# File file.cfg
url = http://example.com
file = main.exe
true = 0 

以下程序读取先前的配置文件:

#include<iostream>
#include<string>
#include<vector>
#include "config_file.h"

int main(void)
{
    // Variables that we want to read from the config file
    std::string url, file;
    bool true_false;

    // Names for the variables in the config file. They can be different from the actual variable names.
    std::vector<std::string> ln = {"url","file","true"};

    // Open the config file for reading
    std::ifstream f_in("file.cfg");

    CFG::ReadFile(f_in, ln, url, file, true_false);
    f_in.close();

    std::cout << "url: " << url << std::endl;
    std::cout << "file: " << file << std::endl;
    std::cout << "true: " << true_false << std::endl;

    return 0;
}

函数 CFG::ReadFile 使用可变参数模板。这样,您可以传递要读取的变量,并使用相应的类型以适当的方式读取数据。

SimpleConfigFile is a library that does exactly what you require and it is very simple to use.

# File file.cfg
url = http://example.com
file = main.exe
true = 0 

The following program reads the previous configuration file:

#include<iostream>
#include<string>
#include<vector>
#include "config_file.h"

int main(void)
{
    // Variables that we want to read from the config file
    std::string url, file;
    bool true_false;

    // Names for the variables in the config file. They can be different from the actual variable names.
    std::vector<std::string> ln = {"url","file","true"};

    // Open the config file for reading
    std::ifstream f_in("file.cfg");

    CFG::ReadFile(f_in, ln, url, file, true_false);
    f_in.close();

    std::cout << "url: " << url << std::endl;
    std::cout << "file: " << file << std::endl;
    std::cout << "true: " << true_false << std::endl;

    return 0;
}

The function CFG::ReadFile uses variadic templates. This way, you can pass the variables you want to read and the corresponding type is used for reading the data in the appropriate way.

手心的温暖 2024-12-04 03:25:53

使用 Shan 的上述答案,我做了一些简单的修改,以便从文件中轻松读取数据,例如:单行中的多个输入,输入后带有“#”的注释选项。

以下是输入文件config.txt

# comments with #
# inputs can be separeted by comma
name=S.Das, age=28 #details
weight=65

这是代码,

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_map>
using std::istringstream;

using std::string;

void readinput(std::unordered_map<string, string>& data) {
    // std::ifstream is RAII, i.e. no need to call close
    std::ifstream cFile("config.txt");
    if (cFile.is_open()) {
        std::string line;
        while (getline(cFile, line)) {
            line.erase(std::remove_if(line.begin(), line.end(), isspace), line.end());
            if (line[0] == '#' || line.empty()) {
                continue;
            } else if (line.find('#')) {
                line = line.substr(0, line.find('#'));
            }
            std::istringstream iss(line);
            string strr;
            while (getline(iss, strr, ',')) {
                auto delimiterPos = strr.find("=");
                auto name         = strr.substr(0, delimiterPos);
                string value      = strr.substr(delimiterPos + 1);
                // std::cout << name << " " << value << '\n';
                data[name] = value;
            }
        }
    } else {
        std::cerr << "Couldn't open config file for reading.\n";
    }
}

int main() {
    std::unordered_map<string, string> data;
    readinput(data);
    std::cout << data.at("age") << std::endl;
    return 0;
}

Using the above answer by Shan, I did some simple modification for easy data reading from files like- multiple inputs in a single line, option for comment with '#' after inputs.

The following is the input file config.txt

# comments with #
# inputs can be separeted by comma
name=S.Das, age=28 #details
weight=65

Here is the code,

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_map>
using std::istringstream;

using std::string;

void readinput(std::unordered_map<string, string>& data) {
    // std::ifstream is RAII, i.e. no need to call close
    std::ifstream cFile("config.txt");
    if (cFile.is_open()) {
        std::string line;
        while (getline(cFile, line)) {
            line.erase(std::remove_if(line.begin(), line.end(), isspace), line.end());
            if (line[0] == '#' || line.empty()) {
                continue;
            } else if (line.find('#')) {
                line = line.substr(0, line.find('#'));
            }
            std::istringstream iss(line);
            string strr;
            while (getline(iss, strr, ',')) {
                auto delimiterPos = strr.find("=");
                auto name         = strr.substr(0, delimiterPos);
                string value      = strr.substr(delimiterPos + 1);
                // std::cout << name << " " << value << '\n';
                data[name] = value;
            }
        }
    } else {
        std::cerr << "Couldn't open config file for reading.\n";
    }
}

int main() {
    std::unordered_map<string, string> data;
    readinput(data);
    std::cout << data.at("age") << std::endl;
    return 0;
}
苍风燃霜 2024-12-04 03:25:52

一般来说,分两个阶段解析此类典型配置文件是最简单的:首先读取各行,然后逐一解析它们。
在 C++ 中,可以使用 std::getline() 从流中读取行。虽然默认情况下它将读取到下一个 '\n' (它将消耗但不返回),您也可以向它传递一些其他分隔符,这使其成为读取的良好候选者up-to-some-char,如示例中的 =

为简单起见,以下假设 = 没有被空格包围。如果您想在这些位置允许空格,则必须策略性地放置 is >>> 。 std::ws 在读取值之前删除键中的尾随空格。然而,在我看来,语法中增加的一点灵活性对于配置文件阅读器来说并不值得这么麻烦。

#include <sstream>
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);
  }
}

(添加错误处理留给读者作为练习。)

In general, it's easiest to parse such typical config files in two stages: first read the lines, and then parse those one by one.
In C++, lines can be read from a stream using std::getline(). While by default it will read up to the next '\n' (which it will consume, but not return), you can pass it some other delimiter, too, which makes it a good candidate for reading up-to-some-char, like = in your example.

For simplicity, the following presumes that the = are not surrounded by whitespace. If you want to allow whitespaces at these positions, you will have to strategically place is >> std::ws before reading the value and remove trailing whitespaces from the keys. However, IMO the little added flexibility in the syntax is not worth the hassle for a config file reader.

#include <sstream>
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);
  }
}

(Adding error handling is left as an exercise to the reader.)

予囚 2024-12-04 03:25:52

正如其他人指出的那样,使用现有的配置文件解析器库而不是重新发明轮子可能会减少工作量。

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

# File: someFile.cfg
url = "http://mysite.com";
file = "main.exe";
true_false = "true";

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

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

Config4Cpp 网站 提供了全面的文档,但仅阅读“入门指南”的第 2 章和第 3 章就足以满足您的需要需要。

As others have pointed out, it will probably be less work to make use of an existing configuration-file parser library rather than re-invent the wheel.

For example, if you decide to use the Config4Cpp library (which I maintain), then your configuration file syntax will be slightly different (put double quotes around values and terminate assignment statements with a semicolon) as shown in the example below:

# File: someFile.cfg
url = "http://mysite.com";
file = "main.exe";
true_false = "true";

The following program parses the above configuration file, copies the desired values into variables and prints them:

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

The Config4Cpp website provides comprehensive documentation, but reading just Chapters 2 and 3 of the "Getting Started Guide" should be more than sufficient for your needs.

心碎的声音 2024-12-04 03:25:52

libconfig 非常简单,而且更好的是,它使用伪 json符号以获得更好的可读性。

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

和链接:-lconfig++

libconfig is very easy, and what's better, it uses a pseudo json notation for better readability.

Easy to install on Ubuntu: sudo apt-get install libconfig++8-dev

and link: -lconfig++

幸福还没到 2024-12-04 03:25:52

一种简单的方法可能如下所示:

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

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

A naive approach could look like this:

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

Now you can access each option value from the global options map anywhere in your program. If you want castability, you could make the mapped type a boost::variant.

空城缀染半城烟沙 2024-12-04 03:25:52

将配置格式化为 JSON,并使用像 jsoncpp 这样的库怎么样?

例如,

{"url": "http://mysite dot com",
"file": "main.exe",
"true": 0}

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

How about formatting your configuration as JSON, and using a library like jsoncpp?

e.g.

{"url": "http://mysite dot com",
"file": "main.exe",
"true": 0}

You can then read it into named variables, or even store it all in a std::map, etc. The latter means you can add options without having to change and recompile your configuration parser.

巡山小妖精 2024-12-04 03:25:52

我一直在寻找像 python 模块 ConfigParser 一样工作的东西,并发现了这个: https://github.com/jtilly/inih

这是 inih 的仅标头 C++ 版本。

inih(INI Not Invented Here)是一个简单的 .INI 文件解析器,用以下语言编写
C. 它只有几页代码,而且它的设计目的是
小而简单,因此非常适合嵌入式系统。这也更多或
与 Python 的 ConfigParser 风格的 .INI 文件兼容性较差,
包括 RFC 822 样式的多行语法和名称:值条目。

I was looking for something that worked like the python module ConfigParser and found this: https://github.com/jtilly/inih

This is a header only C++ version of inih.

inih (INI Not Invented Here) is a simple .INI file parser written in
C. It's only a couple of pages of code, and it was designed to be
small and simple, so it's good for embedded systems. It's also more or
less compatible with Python's ConfigParser style of .INI files,
including RFC 822-style multi-line syntax and name: value entries.

烟燃烟灭 2024-12-04 03:25:52

我最近搜索了我的项目的配置解析库,发现了这些库:

I've searched config parsing libraries for my project recently and found these libraries:

2024-12-04 03:25:52

我将其他解决方案的一些内容合并为对我来说更直观且不易出错的解决方案。我使用公共 stp::map 来跟踪可能的配置 ID,并使用 struct 来跟踪可能的值。就这样:

struct{
    std::string PlaybackAssisted = "assisted";
    std::string Playback = "playback";
    std::string Recording = "record";
    std::string Normal = "normal";
} mode_def;

std::map<std::string, std::string> settings = {
    {"mode", mode_def.Normal},
    {"output_log_path", "/home/root/output_data.log"},
    {"input_log_path", "/home/root/input_data.log"},
};

void read_config(const std::string & settings_path){
std::ifstream settings_file(settings_path);
std::string line;

if (settings_file.fail()){
    LOG_WARN("Config file does not exist. Default options set to:");
    for (auto it = settings.begin(); it != settings.end(); it++){
        LOG_INFO("%s=%s", it->first.c_str(), it->second.c_str());
    }
}

while (std::getline(settings_file, line)){
    std::istringstream iss(line);
    std::string id, eq, val;

    if (std::getline(iss, id, '=')){
        if (std::getline(iss, val)){
            if (settings.find(id) != settings.end()){
                if (val.empty()){
                    LOG_INFO("Config \"%s\" is empty. Keeping default \"%s\"", id.c_str(), settings[id].c_str());
                }
                else{
                    settings[id] = val;
                    LOG_INFO("Config \"%s\" read as \"%s\"", id.c_str(), settings[id].c_str());
                }
            }
            else{ //Not present in map
                LOG_ERROR("Setting \"%s\" not defined, ignoring it", id.c_str());
                continue;
            }
        }
        else{
            // Comment line, skiping it
            continue;
        }
    }
    else{
        //Empty line, skipping it
        continue;            
    }
}

}

I merged bits of the other solutions into something more intuitive and less error prone for me. I use a public stp::map to keep track of the possible config ids, and a struct to keep track of the possible values. Here it goes:

struct{
    std::string PlaybackAssisted = "assisted";
    std::string Playback = "playback";
    std::string Recording = "record";
    std::string Normal = "normal";
} mode_def;

std::map<std::string, std::string> settings = {
    {"mode", mode_def.Normal},
    {"output_log_path", "/home/root/output_data.log"},
    {"input_log_path", "/home/root/input_data.log"},
};

void read_config(const std::string & settings_path){
std::ifstream settings_file(settings_path);
std::string line;

if (settings_file.fail()){
    LOG_WARN("Config file does not exist. Default options set to:");
    for (auto it = settings.begin(); it != settings.end(); it++){
        LOG_INFO("%s=%s", it->first.c_str(), it->second.c_str());
    }
}

while (std::getline(settings_file, line)){
    std::istringstream iss(line);
    std::string id, eq, val;

    if (std::getline(iss, id, '=')){
        if (std::getline(iss, val)){
            if (settings.find(id) != settings.end()){
                if (val.empty()){
                    LOG_INFO("Config \"%s\" is empty. Keeping default \"%s\"", id.c_str(), settings[id].c_str());
                }
                else{
                    settings[id] = val;
                    LOG_INFO("Config \"%s\" read as \"%s\"", id.c_str(), settings[id].c_str());
                }
            }
            else{ //Not present in map
                LOG_ERROR("Setting \"%s\" not defined, ignoring it", id.c_str());
                continue;
            }
        }
        else{
            // Comment line, skiping it
            continue;
        }
    }
    else{
        //Empty line, skipping it
        continue;            
    }
}

}

垂暮老矣 2024-12-04 03:25:52

为什么不尝试一些简单且人类可读的东西,比如 JSON(或 XML)?

有许多用于 C++ 的 JSON(或 XML)的预制开源实现 - 我会使用其中之一。

如果你想要更多“二进制”的东西 - 尝试 BJSON 或 BSON :)

Why not trying something simple and human-readable, like JSON (or XML) ?

There are many pre-made open-source implementations of JSON (or XML) for C++ - I would use one of them.

And if you want something more "binary" - try BJSON or BSON :)

神妖 2024-12-04 03:25:52

我正在寻找类似的简单 C++ 配置文件解析器,本教程网站 为我提供了一个基本但有效的解决方案。完成工作的灵魂是快速而肮脏的。

myConfig.txt

gamma=2.8
mode  =  1
path = D:\Photoshop\Projects\Workspace\Images\

以下程序读取之前的配置文件:

#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>

int main()
{
    double gamma = 0;
    int mode = 0;
    std::string path;

    // std::ifstream is RAII, i.e. no need to call close
    std::ifstream cFile("myConfig.txt");
    if (cFile.is_open())
    {
        std::string line;
        while (getline(cFile, line)) 
        {
            line.erase(std::remove_if(line.begin(), line.end(), isspace),line.end());
            if (line[0] == '#' || line.empty()) continue;

            auto delimiterPos = line.find("=");
            auto name = line.substr(0, delimiterPos);
            auto value = line.substr(delimiterPos + 1);

            //Custom coding
            if (name == "gamma") gamma = std::stod(value);
            else if (name == "mode") mode = std::stoi(value);
            else if (name == "path") path = value;
        }
    }
    else 
    {
        std::cerr << "Couldn't open config file for reading.\n";
    }

    std::cout << "\nGamma=" << gamma;
    std::cout << "\nMode=" << mode;
    std::cout << "\nPath=" << path;
    std::getchar();
}

I was searching for a similar simple C++ config file parser and this tutorial website provided me with a basic yet working solution. Its quick and dirty soultion to get the job done.

myConfig.txt

gamma=2.8
mode  =  1
path = D:\Photoshop\Projects\Workspace\Images\

The following program reads the previous configuration file:

#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>

int main()
{
    double gamma = 0;
    int mode = 0;
    std::string path;

    // std::ifstream is RAII, i.e. no need to call close
    std::ifstream cFile("myConfig.txt");
    if (cFile.is_open())
    {
        std::string line;
        while (getline(cFile, line)) 
        {
            line.erase(std::remove_if(line.begin(), line.end(), isspace),line.end());
            if (line[0] == '#' || line.empty()) continue;

            auto delimiterPos = line.find("=");
            auto name = line.substr(0, delimiterPos);
            auto value = line.substr(delimiterPos + 1);

            //Custom coding
            if (name == "gamma") gamma = std::stod(value);
            else if (name == "mode") mode = std::stoi(value);
            else if (name == "path") path = value;
        }
    }
    else 
    {
        std::cerr << "Couldn't open config file for reading.\n";
    }

    std::cout << "\nGamma=" << gamma;
    std::cout << "\nMode=" << mode;
    std::cout << "\nPath=" << path;
    std::getchar();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文