读key-value型配置文件解析的改进 持续更新改进

本文介绍了一个配置文件(domain-white-list)的解析方法,通过C++代码实现了解析逻辑,包括如何读取配置文件、解析配置项并利用哈希映射存储IP地址与域名,特别关注于域名中的通配符处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

group{
servers = {“111.13.111.233”,”192.168.22.1”},
domains = {
“www.vip.com”,
“*.163.com”,
}
}
group{
servers = {“111.13.111.234”, 这个是注释
“10.10.110.123”
},
domains = {
“1.qtmojo.com”,
“a1.alicdn.com”,
}
}
这个就是配置文件,文件名为domain-white-list,之前写的那个hash_map函数中对这个配置文件的解析太”简陋”了.
改进版本代码如下

#include<iostream>
#include<ext/hash_map>
#include<vector>
#include<sstream>   
#include<fstream>
#include<string>

std::vector<std::vector<std::string>*>servers;
std::vector<std::string>ip;
std::vector<std::string>domain;

class hm_strcmp
{
    public:
    bool operator()(const std::string& s1,const std::string& s2) const
    {
        return s1==s2;
    }
};
struct str_hash
{
    size_t operator()(const std::string &str) const
    {
        unsigned long __h=0;
        for(size_t i=0;i<str.size();i++)
        __h=5*__h+str[i];
        return size_t(__h);
    }

};


__gnu_cxx::hash_map<std::string,int,str_hash,hm_strcmp> domain_black_hash;
__gnu_cxx::hash_map<std::string,int,str_hash,hm_strcmp> black_head_hash;
__gnu_cxx::hash_map<std::string,int,str_hash,hm_strcmp> black_rear_hash;
str_hash,hm_strcmp> domain_black_hash;
__gnu_cxx::hash_map<std::string, std::vector<std::string>*,str_hash,hm_strcmp> domain_hash;
__gnu_cxx::hash_map<std::string, std::vector<std::string>*,str_hash,hm_strcmp> head_hash;
__gnu_cxx::hash_map<std::string, std::vector<std::string>*,str_hash,hm_strcmp> rear_hash;

class dns_conf {
public:
    void open_conf_file();
    void close_conf_file();
    int parse_white_conf();
    int parse_black_conf();
public:
    std::string      cfilename;
    std::ifstream    cfilestream;
    int          lineNum;
    int         block_index;
    int  unkown_block_start;
};
/*传入域名,传出点数,传出标记
标记:返回1前缀 返回2后缀 返回0正常
返回值:*的位置
*/
int posAfterStar(const char *str, int &point_num, char &wildcard_flash) {
    if (!str) {
        return 0;
    }
    const char *_p = str;
    char c = *_p;
    int  pos = 0;
    point_num = 0;
    while (*_p) {
        if (c == '*') {
            pos = _p + 1 - str;
            if (point_num == 0)
            {
                wildcard_flash = '1';
            }
            else
            {
                wildcard_flash = '2';
            }
        }
        else if (c == '.') {
            point_num++;
        }
        _p += 1;
        c = *_p;
    }
    return pos;
}


void dns_conf::open_conf_file() {
    //cfilename = "./dns_conf.file";
    cfilename = "./domain-white-list";
    try
    {
        cfilestream.open(cfilename);
        if (!cfilestream.is_open()) {
            //std::cerr << "open " << cfilename << " failed \n";
            std::cout << "open err" << std::endl;
            std::exit(1);
        }
        std::cout << "open success" << std::endl;
    }
    catch (std::exception &e) {
        std::cerr << e.what() << std::endl;
        std::exit(1);
    }
}

void dns_conf::close_conf_file() {
    if (cfilestream.is_open()) {
        cfilestream.close();
    }
}

int dns_conf::parse_black_conf()
{
    char ch;
    int pn;
    char flag='0';
    int line_num=0;
    std::ostringstream _strline;
    while (cfilestream.get(ch)) {
        //std::cout<<"ch:"<<ch <<"  ascii:"<<(int)ch<<std::endl;    
        if(ch == '\n')
        {
            line_num++;
            posAfterStar(_strline.str().c_str(), pn, flag);
            std::cout<<"domain:"<<_strline.str();
            std::cout<<"   flag:"<<flag<<std::endl;

           if(flag == '0') 
           {
                domain_black_hash.insert(__gnu_cxx::hash_map<std::string, int>::value_type(_strline.str(), line_num));
           }
           else if(flag=='1')
           {
                black_head_hash.insert(__gnu_cxx::hash_map<std::string, int>::value_type(_strline.str().erase(0,1), line_num));
           }
           else if(flag=='2')
           {
                black_rear_hash.insert(__gnu_cxx::hash_map<std::string, int>::value_type(_strline.str().substr(0, _strline.str().find("*")), line_num));
           }
           flag='0'; 
            _strline.str("");

            continue;
        }
        _strline << ch;
    }
}

int dns_conf::parse_white_conf()
{
    char ch;
    int block_num = 0;
    int block_end_num = 0;
    int ref_num = 0;
    std::ostringstream _strline;
    int new_flag = 0;
    int group_flag = 1;//flag=0时 在一个组
    std::vector<std::string>* p=NULL;//存ip
    int group=0;//第几组

    int servers_flag=0;//servers开始
    int domains_flag=0;//domains开始

    while (cfilestream.get(ch)) {
        if(ch == '{')
            block_num++;
        if(ch == '}')
            block_num--;
        if(block_num == 0)
         {   //当一个组结束 置标志位,同时清空_strline
         //不能清空
            group_flag=1;
            //_strline.str("");
         }

        if(block_num == 1 && group_flag == 1) 
        {
            //每一个组的开始,只进来一次
            group++;
            //std::cout<<"组名:"<<_strline.str()<<"  第"<<group<<"组"<<std::endl;
            std::cout<<"  第"<<group<<"组"<<std::endl;

            group_flag=0;
            _strline.str("");
        }
        if(ch == '=')//一个小组开始 , 假设小组里不再嵌套
        {
            if(_strline.str().find("servers",0) != -1)
            {
                servers_flag = 1;
            }else if(_strline.str().find("domains",0) != -1)
            {
                domains_flag = 1;
            }
            else
            {
                std::cout<<"not exist the key"<<std::endl;
                return 1;
            }
        }
        if(servers_flag == 1)//解析servers小组
        {
            if (new_flag == 0)//只进来一次
            {
                std::vector<std::string>* new_p = new std::vector < std::string >;
                p = new_p;
                servers.push_back(p);
                new_flag = 1;
                _strline.str("");
            }
            if (ch == '"')
            {
                ref_num++;
                if(ref_num == 1)
                    _strline.str("");//第一个" 则立即清空_strline
                continue;
            }
            if (ref_num == 2)
            {
                std::cout<<"ip: "<<_strline.str()<<std::endl;
                (*p).push_back(_strline.str());
                _strline.str("");
                ref_num = 0;
            }
            if(ch == '}')    //一个小组的结束标志.但是如果有嵌套 那就得修改了
            {
                servers_flag = 0;
                _strline.str("");
            }
        }
        if( domains_flag == 1)//解析域名小组
        {
            //这之前ref_num必须为0
            if (ch == '"')
            {
                ref_num++;
                if(ref_num == 1)
                    _strline.str("");//第一个" 则立即清空_strline
                continue;
            }
            if (ref_num == 2)
            {
                int pn; char flag = '0';
                //_strline << '.';
                std::cout<<"domain: "<<_strline.str()<<std::endl;
                posAfterStar(_strline.str().c_str(), pn, flag);
                if (flag == '0')
                {
                    //普通                domain_hash.insert(__gnu_cxx::hash_map<std::string, std::vector<std::string>*>::value_type(_strline.str(), p));
                }
                else if (flag == '1')
                {
                    //前缀  //需要去掉前缀的* 
                    head_hash.insert(__gnu_cxx::hash_map<std::string, std::vector<std::string>*>::value_type(_strline.str().erase(0,1), p));
                }
                else if (flag == '2')
                {   
                    //后缀  //需要去掉后缀的*
                    //std::cout << "后缀:" << _strline.str().substr(0, _strline.str().find("*")) << std::endl;
                    rear_hash.insert(__gnu_cxx::hash_map<std::string, std::vector<std::string>*>::value_type(_strline.str().substr(0, _strline.str().find("*")), p));
                }
                domain.push_back(_strline.str());
                _strline.str("");
                ref_num = 0;
            }
            if(ch == '}')
            {
                domains_flag = 0;
                _strline.str("");
            }
        }
        _strline << ch;
    }
    if(block_num != 0)
    {
        std::cout<<"block not match"<<std::endl;
        return 1;
    }
    return 0;
}

int main()
{
    dns_conf conf;
    conf.open_conf_file();
    int ret=conf.parse_white_conf();
    if( 1 == ret)
    {
        std::cout<<"parse err"<<std::endl;
    }
    else if( 0 == ret)
    {
        std::cout<<"parse success"<<std::endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值