map是STL的一个关联容器,map的特性就是它提供一对一的数据处理能力,其中第一个可以称为关键字(key),每个关键字只能在map中出现一次,第二个可能称为该关键字的值(value),由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。
今天主要讲的是如何使用map来获取一个文件的实值(value)和键值(key)。
map使用
map以红黑树为底层机制,map把值与键关联在一起,可以使用键来查找词。使用map得包含map类所在的头文件 #include
domain.rc
key=google.com;value=GOOGLE_VIDEO
key=facebook.com;value=FACEBOOK_VIDEO
key=youtube.com;value=YOUTUBE_LIVE
key=bilibili.com;value=VIDEO
key=www.google.com,video;value=VIDEO
上面的文件非常直观,我们在程序中可以定义为:map<string,string> mRst;
key为关键字,每个关键字只能在map中出现一次,value为该关键字的值。键可以是基本类型,string经常被用来作为键。value的基本类型也是string。
实例
对于上面的文件(domain.rc),如果我们想要获取到key和value应该怎么弄呢? 这个时候就需要写一个切割函数,主要对符号,
和;
、=
进行切割,然后放到容器中。
//对str按delimiter进行切割,并保存到svec中,返回一共切割的个数
int UtlSpilit(const string& Line, vector<string>& Svec, const string& Delimit, int Count)
{
Svec.clear();
if(Delimit.empty() || Count < 0 || Line.empty())
return 0;
if(Count == 0)
Count = numeric_limits<int>::max();
string::size_type bPos=0;
string::size_type ePos=0;
int NowCount=1;
//string中find()返回值是字母在母串中的位置(下标记录),如果没有找到,那么会返回一个特别的标记npos
while((ePos = Line.find(Delimit, bPos)) != string::npos && NowCount<Count)
{
/*获得字符串Line中从第bPos位开始的长度为ePos-bPos的字符串*/
string tmpLine=Line.substr(bPos, ePos-bPos);
Svec.push_back(tmpLine);/*顺序容器,存放string类型的对象。*/
bPos=ePos+Delimit.size();
++NowCount;
}
string tmpLine = Line.substr(bPos);
Svec.push_back(tmpLine);
return Svec.size();/*返回切割个数*/
}
切割文件中符号;
和=
int UtlParseOpts(const string &strVal, map<string, string> &mapOpts,
const string &strMainToken, const string &strSlaveToken)
{
vector<string> vOpts;
utl_spilit(strVal.c_str(), vOpts, strMainToken, 0);
for(unsigned i = 0; i < vOpts.size(); i++)
{
vector<string> vKv;
utl_spilit(vOpts[i].c_str(), vKv, strSlaveToken, 0);
if ( vKv.size() != 2)
continue;
mapOpts[vKv[0]] = vKv[1];
}
return 0;
};
解析文件(domain.rc)
void ParserRcFile(char* szCfgPath,list<Cfg> &lstRcConfs)
{
FILE *pFp = fopen(szCfgPath, "r");
if (pFp == 0)
{
return ;
}
char szLine[1024];
for(;;)
{
char *pLine = fgets(szLine, sizeof(szLine)-1, pFp);
if (pLine == 0)
break;
if (!pLine || pLine[0] == '#')
continue;
char *pTmp = strrchr(pLine, '\n');
if (pTmp != 0)
*pTmp = 0;
pTmp = strrchr(pLine, '\r');
if (pTmp != 0)
*pTmp = 0;
map<string,string> mRst;//以string为键值,以string为值
/*format:key=google.com;value=FACEBOOKVIDEO*/
utl_parse_opts(pLine, mRst, ";", "=");
string strKeys = mRst["key"];
string strValue = mRst["value"];
printf("strKeys = %s\n", strKeys.c_str());
printf("strValue = %s\n", strValue.c_str());
vector<string> vKeys;
utl_spilit(strKeys, vKeys, ",", 0);
Cfg cfg;
for (string & s : vKeys)
{
cfg.m_iValue.push_back(s);
}
cfg.m_iProt = strValue;
lstRcConfs.push_back(cfg);
}
fclose(pFp);
}
指定的流中读取数据,每次读取一行。对文件中第一个字符#
跳过,这样方便注释。查找字符在指定字符串中从右面开始的第一次出现\n
,\r
的位置 ,定义一个map存放切割实值(value)和键值(key)。
完整代码:
#include <list>
#include <vector>
#include <map>
#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <limits>
using std::numeric_limits;
using std::list;
using std::vector;
using std::map;
using std::string;
struct Cfg
{
vector<string> m_vIdxs;
string m_iValue;
};
//对str按delimiter进行切割,并保存到svec中,返回一共切割的个数
int UtlSpilit(const string& Line, vector<string>& Svec, const string& Delimit, int Count)
{
Svec.clear();
if(Delimit.empty() || Count < 0 || Line.empty())
return 0;
if(Count == 0)
Count = numeric_limits<int>::max();
string::size_type bPos=0;
string::size_type ePos=0;
int NowCount=1;
while((ePos = Line.find(Delimit, bPos)) != string::npos && NowCount<Count)
{
string tmpLine=Line.substr(bPos, ePos-bPos);
Svec.push_back(tmpLine);
bPos=ePos+Delimit.size();
++NowCount;
}
string tmpLine = Line.substr(bPos);
Svec.push_back(tmpLine);
return Svec.size();
}
int UtlParseOpts(const string &strVal, map<string, string> &mapOpts,
const string &strMainToken, const string &strSlaveToken)
{
vector<string> vOpts;
UtlSpilit(strVal.c_str(), vOpts, strMainToken, 0);
for(unsigned i = 0; i < vOpts.size(); i++)
{
vector<string> vKv;
UtlSpilit(vOpts[i].c_str(), vKv, strSlaveToken, 0);
if ( vKv.size() != 2)
continue;
mapOpts[vKv[0]] = vKv[1];
}
return 0;
};
void ParserRcFile(char* szCfgPath,list<Cfg> &lstRcConfs)
{
FILE *pFp = fopen(szCfgPath, "r");
if (pFp == 0)
{
return ;
}
char szLine[1024];
for(;;)
{
char *pLine = fgets(szLine, sizeof(szLine)-1, pFp);
if (pLine == 0)
break;
if (!pLine || pLine[0] == '#')
continue;
char *pTmp = strrchr(pLine, '\n');
if (pTmp != 0)
*pTmp = 0;
pTmp = strrchr(pLine, '\r');
if (pTmp != 0)
*pTmp = 0;
map<string,string> mRst;
/*format:key=google.com;value=FACEBOOKVIDEO*/
UtlParseOpts(pLine, mRst, ";", "=");
string strKeys = mRst["key"];
string strValue = mRst["value"];
printf("strKeys = %s\n", strKeys.c_str());
printf("strValue = %s\n", strValue.c_str());
vector<string> vKeys;
utl_spilit(strKeys, vKeys, ",", 0);
printf("vKeys =%s\n", vKeys);
Cfg cfg;
for (string & s : vKeys)
{
cfg.m_vIdxs.push_back(s);
}
cfg.m_iValue= strValue;
lstRcConfs.push_back(cfg);
}
fclose(pFp);
}
int main(int argc, char const *argv[])
{
char szListFilef[256] = {0};
snprintf( szListFilef, sizeof(szListFilef),"./domain.rc");
list<Cfg> lstRcConfs;
ParserRcFile(szListFilef,lstRcConfs);
return 0;
}
编译输出:
总结
map是STL的一个关联容器,它提供一对一的hash。第一个可以称为关键字(key),每个关键字只能在map中出现一次;第二个可能称为该关键字的值(value),key 和 value可以是任意你需要的类型。
本篇文章只是简单介绍map工作中的常见用法,没有对内部源码的研究和所有map基本操作函数的使用。
欢迎关注微信公众号【程序猿编码】,添加本人微信号(17865354792),回复:领取学习资料。或者回复:进入技术交流群。网盘资料有如下: