配置文件读取

config_parser.h:

#ifndef CONFIG_PARSER_H
#define CONFIG_PARSER_H
#include <exception>
#include <stdio.h>
#include <string>
#include <map>

class ConfigValue
{
public:
    ConfigValue(std::string & value);

    std::string asString() const;
    int32_t asInt32() const;
    int64_t asInt64() const;
private:
    std::string & m_value;
};

class ConfigKey
{
public:
    ConfigKey(std::map<std::string, std::string> & keys);

    ConfigValue operator[](const std::string& key_name);
private:
    std::map<std::string, std::string> & m_keys;
};

class ConfigParser
{
public:
    ConfigParser(std::string filename);

    std::map<std::string, std::string> & get_section(const std::string& section_name);

    ConfigKey operator[](const std::string& section_name);

    void dump(FILE* log_file);
private:
    std::string read_header(const std::string& line);

    void read_configuration(const std::string& line, const std::string& header);

    // trim from start (in place)
    void ltrim(std::string &s);

    // trim from end (in place)
    void rtrim(std::string &s);

    // trim from both ends (in place)
    void trim(std::string &s);

    // trim from start (copying)
    std::string ltrim_copy(std::string s);

    // trim from end (copying)
    std::string rtrim_copy(std::string s);

    // trim from both ends (copying)
    std::string trim_copy(std::string s);

private:
    std::map<std::string, std::map<std::string, std::string> > m_sections;
};
#endif

config_parser.cpp:

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

#include "config_parser.h"

ConfigValue::ConfigValue(std::string & value):m_value(value)
{

}

std::string ConfigValue::asString() const
{
    return m_value;
}

int32_t ConfigValue::asInt32() const
{
    return std::atoi(m_value.c_str());
}

int64_t ConfigValue::asInt64() const
{
    return std::atol(m_value.c_str());
}

ConfigKey::ConfigKey(std::map<std::string, std::string> & keys):m_keys(keys)
{

}

ConfigValue ConfigKey::operator[](const std::string& key_name)
{
    ConfigValue value(m_keys[key_name]);
    return value;
}

ConfigParser::ConfigParser(std::string filename)
{
    std::ifstream fin(filename);

    if (fin.good())
    {
        std::string line;
        std::string current_header = "";
        while (std::getline(fin, line))
        {
            trim(line);

            // Skip empty lines
            if (line.size() == 0)
                continue;

            switch (line[0])
            {
                case '#':
                case ';':
                    // Ignore comments
                    break;
                case '[':
                    // Section header
                    current_header = read_header(line);
                    break;
                default:
                    // Everything else will be configurations
                    read_configuration(line, current_header);
            }
        }
        fin.close();
    }
    else
    {
        throw std::runtime_error("File `" + filename + "` does not exist");
    }
}

std::map<std::string, std::string> & ConfigParser::get_section(const std::string& section_name)
{
    if(m_sections.count(section_name) == 0)
    {
        std::string error = "No such key: `" + section_name + "`";
        throw std::out_of_range(error);
    }
    return m_sections.at(section_name);
}

ConfigKey ConfigParser::operator[](const std::string& section_name)
{
    return ConfigKey(get_section(section_name));
}

void ConfigParser::dump(FILE* log_file)
{
    // Set up iterators
    std::map<std::string, std::string>::iterator itr1;
    std::map<std::string, std::map<std::string, std::string> >::iterator itr2;
    for(itr2 = m_sections.begin(); itr2 != m_sections.end(); itr2++)
    {
        fprintf(log_file, "[%s]\n", itr2->first.c_str());
        for(itr1 = itr2->second.begin(); itr1 != itr2->second.end(); itr1++)
        {
            fprintf(log_file, "%s=%s\n", itr1->first.c_str(), itr1->second.c_str());
        }
    }
}

std::string ConfigParser::read_header(const std::string& line)
{
    if (line[line.size() - 1] != ']')
        throw std::runtime_error("Invalid section header: `" + line + "`");
    return trim_copy(line.substr(1, line.size() - 2));
}

void ConfigParser::read_configuration(const std::string& line, const std::string& header)
{
    if (header == "")
    {
        std::string error = "No section provided for: `" + line + "`";
        throw std::runtime_error(error);
    }

    if (line.find('=') == std::string::npos)
    {
        std::string error = "Invalid configuration: `" + line + "`";
        throw std::runtime_error(error);
    }

    std::istringstream iss(line);
    std::string key;
    std::string val;
    std::getline(iss, key, '=');

    if (key.size()== 0)
    {
        std::string error = "No key found in configuration: `" + line + "`";
        throw std::runtime_error(error);
    }

    std::getline(iss, val);

    m_sections[header][trim_copy(key)] = trim_copy(val);
}

// trim from start (in place)
void ConfigParser::ltrim(std::string &s)
{
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
                return !std::isspace(ch);
                }));
}

// trim from end (in place)
void ConfigParser::rtrim(std::string &s)
{
    s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
                return !std::isspace(ch);
                }).base(), s.end());
}

// trim from both ends (in place)
void ConfigParser::trim(std::string &s)
{
    ltrim(s);
    rtrim(s);
}

// trim from start (copying)
std::string ConfigParser::ltrim_copy(std::string s)
{
    ltrim(s);
    return s;
}

// trim from end (copying)
std::string ConfigParser::rtrim_copy(std::string s)
{
    rtrim(s);
    return s;
}

// trim from both ends (copying)
std::string ConfigParser::trim_copy(std::string s)
{
    trim(s);
    return s;
}

main.cpp:

#include <iostream>
#include <string>

#include "config_parser.h"

int main()
{
    ConfigParser config("example.ini");

    std::cout <<  config["section1"]["key1"].asString() << std::endl;
    std::cout <<  config["section1"]["key2"].asString() << std::endl;
    std::cout <<  config["section 2"]["key 1"].asInt32() << std::endl;

    return 0;
}

example.ini:

# Comment
; Comment
[section1]
key1=this is value1
key2=123
[section 2]
key 1=432413

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值