c++实现通用参数解析类示例
main.cpp
#include <iostream>
#include <getopt.h>
#include "parsingargs.h"
#include <string.h>
using namespace std;
int main(int argc, char * argv[])
{
//string tmpPara = "-p \"4567\" --out 1.log "; //ok
//string tmpPara = "xxxx -p \"4567\" --out 1.log ";//ok
//string tmpPara = "-p \"4567\" --out 1.log 2.log"; //ok
string tmpPara = "";
for(int i=1;i <argc; i++)
{
cout << i << "=" << argv[i] <<"---"<< endl;
if(strlen(argv[i]) == 0) //处理空字符串
{
cout << "find NULL" << endl;
tmpPara += char(31);
}
else
{
tmpPara += argv[i];
}
tmpPara += " ";
}
std::map<std::string, std::vector<std::string> > result;
ParsingArgs pa;
pa.AddArgType('l',"getlist", ParsingArgs::NO_VALUE);
pa.AddArgType('p',"getuser", ParsingArgs::MAYBE_VALUE);
pa.AddArgType('o',"outFile", ParsingArgs::MUST_VALUE);
bool bExit = false;
do
{
result.clear();
cout << "input is:" << tmpPara << "---size = " << tmpPara.size()<< endl;
std::string errPos;
int iRet = pa.Parse(tmpPara,result, errPos);
if(0>iRet)
{
cout << "参数错误" << iRet << errPos << endl;
}
else
{
map<std::string, std::vector<std::string> >::iterator it = result.begin();
for(; it != result.end(); ++it)
{
cout << "key=" << it->first<<endl;
for(int i=0; i<it->second.size(); ++i)
{
cout << " value =" << it->second[i] << "------" << endl;
}
}
}
string str;
cout << ">>> ";
getline(cin, tmpPara);
if(0 == tmpPara.compare("exit"))
{
bExit = true;
}
}while(!bExit);
return 0;
}
parsingargs.h
#ifndef PARSINGARGS_H
#define PARSINGARGS_H
/* purpose @ 解析输入的参数,需先通过AddArgType将必须参数和可允许的参数key加入到判定列表中
* 通过Parse中的result将结果返回,其中结果的key为合法的key,vecotr为参数列表
* 参数列表支持去掉参数前后的引号和\对引号和\的转义
*
* 特殊合法字段:
* 格式 实际存储值
* \\value\" \value"
* "\\\value\"" \value"
*
* 注意事项:
* 1、输入参数列表中参数分隔以空格区分
* 2、- 后跟单字符关键字,--后跟长字符串关键字
* 3、关键字不能重复出现,长短关键字不能同时出现在参数列表,否则会Parse函数会提示参数错误
*
* 用法:
* ParsingArgs pa;
* pa.AddArgType('l',"getlist", ParsingArgs::NO_VALUE); //NO_VALUE关键字后不能有参数
* pa.AddArgType('p',"getuser", ParsingArgs::MAYBE_VALUE); //MAYBE_VALUE 关键字后可能有关键字
* pa.AddArgType('o',"outFile", ParsingArgs::MUST_VALUE); // MUST_VALUE 关键字后必须有参数
* std::map<std::string, std::vector<std::string> > result;
* int iRet = pa.Parse(tmpPara,result); //result以输入关键字为key存储相关的值序列
*
* date @ 2014.02.19
* author @ haibin.wang
*
*/
#include <map>
#include <vector>
#include <string>
class ParsingArgs
{
public:
ParsingArgs();
~ParsingArgs();
enum KeyFlag{ INVALID_KEY=-1, NO_VALUE, MAYBE_VALUE, MUST_VALUE};
/* pur @ 添加解释参数,一个参数可以是长参数,也可以是缩写的段参数,短参数只能为单字符,longName和shortName至少要有一个
* para @ shortName 短参数名,0为不要短参数
* para @ longName 长参数名 ,NULL为不要长参数
* para @ flag 是否需要参数,0不需要,1必须要,2可要可不要
* return @ true 添加成功,false添加失败
*/
bool AddArgType(const char shortName, const char * longName = NULL, KeyFlag flag=NO_VALUE);
/* pur @ 根据参数类型解释传入的字符串
* para @ paras 需要解释的字符串
* para @ result 返回解析后的结果
* para @ errPos 当错误的时候返回出错的大概位置
* return @ 0 解释成功,负数 解释失败
* -1 未知参数错误
-2 不能有参数的选项有参数错误
* -3 必有参数选项后没有跟参数
* -4 关键字没有加入到AddArgType中
* -5 关键字重复
*/
int Parse(const std::string & paras, std::map<std::string, std::vector<std::string> > & result, std::string &errPos);
private:
/* pur @ 判定传入的参数是否是已经添加的参数类型,如果是则去掉-或--,并返回
* para @ key 要判定的参数
* return @ -1 不是合法参数类型 否则返回Option中的flag
*/
KeyFlag GetKeyFlag(std::string &key);
/* pur @ 删除关键字前的-或--
*/
void RemoveKeyFlag(std::string & paras);
/* pur @ 从Paras中获取一个单词,自动过滤掉单词前后引号,并实现\对空格和引号的转义
* para @ Paras 返回第一个单词后的所有内容
* para @ word 返回第一单词
* return @ 成功返回true,false失败
*/
bool GetWord(std::string & Paras, std::string & word);
/* pur @ 检查关键字是否重复
* para @ key 被检查的关键字
* para @ result已存储的关键字序列
* return @ true 是重复的,false不重复
*/
bool IsDuplicateKey(const std::string &key, const std::map<std::string, std::vector<std::string> > & result);
struct Option
{
std::string m_longName;
char m_shortName;
KeyFlag m_flag;
};
std::vector<Option> m_args; //参数信息列表
};
#endif
parsingargs.cpp
#include "parsingargs.h"
#include <list>
ParsingArgs::ParsingArgs()
{
}
ParsingArgs::~ParsingArgs()
{
}
bool ParsingArgs::AddArgType(char shortName, const char * longName, KeyFlag flag)
{
if(NULL == longName && 0 == shortName)
{
return false;
}
Option tmp;
tmp.m_longName = longName;
tmp.m_shortName = shortName;
tmp.m_flag = flag;
m_args.push_back(tmp);
return true;
}
ParsingArgs::KeyFlag ParsingArgs::GetKeyFlag(std::string &key) //返回flag,
{
for(int i=0; i<m_args.size(); ++i)
{
std::string shortName = "-";
std::string longName = "--";
shortName += m_args[i].m_shortName;
longName += m_args[i].m_longName;
if( 0 == key.compare(shortName) ||
(0==key.compare(longName))
)
{
RemoveKeyFlag(key);
return m_args[i].m_flag;
}
}
return INVALID_KEY;
}
void ParsingArgs::RemoveKeyFlag(std::string & word)
{
if(word.size()>=2)
{
if(word[1] == '-')
{
word.erase(1,1);
}
if(word[0] == '-')
{
word.erase(0,1);
}
}
}
/* pur @ 从Paras中获取一个单词,自动过滤掉单词前后引号,并实现\对空格和引号的转义
* para @ Paras 返回第一个单词后的所有内容
* para @ word 返回第一单词
* return @ 成功返回true,false失败
*/
bool ParsingArgs::GetWord(std::string & Paras, std::string & word)
{
size_t iNotSpacePos = Paras.find_first_not_of(' ',0);//查找第一个非空格字符位置
if(iNotSpacePos == std::string::npos)
{
Paras.clear();
word.clear();
return true;
}
int length = Paras.size();
std::list<char> specialChar;
int islashPos = -1;
for(int i=iNotSpacePos; i<length; i++)
{
char cur=Paras[i];
bool bOk = false;
switch(cur)
{
case ' ':
if(specialChar.empty())
{
if(i!=(length-1))
{
Paras = std::string(Paras, i+1, length-i-1);
}
else
{//最后一个是空格
Paras.clear();
}
bOk = true;
}
else
{
if(specialChar.back() == '\\')
{
specialChar.pop_back();
}
word.append(1,cur);
}
break;
case '"':
if(specialChar.empty())
{
specialChar.push_back(cur);
}
else if(specialChar.back() == cur)
{ //找到匹配的括号
specialChar.pop_back();
}
else if(specialChar.back() == '\\')
{
word.append(1,cur);
specialChar.pop_back();
}
else
{
word.clear();
return false;
}
break;
case '\\':
if(specialChar.empty())
{
specialChar.push_back(cur);
islashPos = i;
}
else if(specialChar.back() == '"')
{
if(i<(length-1))
{
if('"'==Paras[i+1] || '\\'==Paras[i+1])
{
specialChar.push_back(cur);
}
else
{
word.append(1,cur);
}
}
else
{
word.clear();
return false;
}
}
else if('\\' == specialChar.back())
{
word.append(1,cur);
specialChar.pop_back();
}
else
{
word.clear();
return false;
}
break;
default:
word.append(1,Paras[i]);
if(i==(length-1))
{
bOk = true;
Paras.clear();
}
break;
}
if(bOk)
{
return true;
}
}//for end
if(specialChar.empty())
{
Paras.clear();
return true;
}
else
{
return false;
}
}
bool ParsingArgs::IsDuplicateKey(const std::string &key, const std::map<std::string, std::vector<std::string> > & result)
{
if(result.find(key) != result.end())
{
return true; //关键字重复
}
for(int i=0; i<m_args.size(); ++i)
{
if( (key.compare(m_args[i].m_longName) == 0 && result.find(std::string(1, m_args[i].m_shortName)) != result.end())
|| (key.compare(std::string(1, m_args[i].m_shortName)) == 0 && result.find(m_args[i].m_longName) != result.end())
)
{
return true;
}
}
return false;
}
int ParsingArgs::Parse(const std::string & Paras, std::map<std::string, std::vector<std::string> > & result, std::string &errPos)
{
std::string tmpString = Paras;
KeyFlag keyFlag = INVALID_KEY; //参数标识
std::string sKey = ""; //key关键字
bool bFindValue = false; //是否已经有value
while(!tmpString.empty())
{
std::string word = "";
bool bRet = GetWord(tmpString, word);
if(bRet == false)
{
errPos = tmpString;
return -4;//参数解析错误
}
else
{
KeyFlag tmpFlag = GetKeyFlag(word);
if(IsDuplicateKey(word, result))
{
errPos = tmpString;
return -5;
}
if(tmpFlag != INVALID_KEY)
{
if(tmpFlag == MUST_VALUE && keyFlag == MUST_VALUE && !bFindValue)
{
errPos = tmpString;
return -3;
}
keyFlag = tmpFlag;
std::vector<std::string> tmp;
result[word] = tmp;
sKey = word;
bFindValue = false;
}
else
{
switch(keyFlag)
{
case MAYBE_VALUE:
case MUST_VALUE:
{
std::map<std::string, std::vector<std::string> >::iterator it = result.find(sKey);
if(it != result.end())
{
it->second.push_back(word);
bFindValue = true;
}
else
{
errPos = tmpString;
return -1;// 没有发现相关的key
}
}
break;
case NO_VALUE:
errPos = tmpString;
return -2; //不能有参数的选项后有参数
default:
errPos = tmpString;
return -1;//参数错误
}//switch end
}
}
}//while end
return 0;
}
相关文章
- vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
- 这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
- 这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- 本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
- 本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
- 整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
- 这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-28
- 这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
- 这篇文章主要介绍了Vue 组件复用多次自定义参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-27
- 这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
- 这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
PHP中empty和isset对于参数结构的判断及empty()和isset()的区别
废话不多说了,直接给大家贴代码了。<?php class test{} $a1 = null; $a2 = ""; //$a3 = $a4 = 0; $a5 = '0'; $a6 = false; $a7 = array(); //var $a8; $a9 = new test(); for ($i=1; $i <=9 ; $i++) {...2015-11-24- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
- 这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- mysql安装成功后有几个默认的配置模板,列表如下: my-huge.cnf : 用于高端产品服务器,包括1到2GB RAM,主要运行mysql my-innodb-heavy-4G.ini : 用于只有innodb的安装,最多有4GB RAM,支持大的查询和低流量 my-large.cnf : 用于...2015-03-15
- 本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
- 这篇文章主要介绍了C#泛型的类型参数约束的相关资料,文中讲解非常细致,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下...2020-07-31
- 这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
- 这篇文章主要给大家介绍了关于C#中out参数、ref参数与值参数的用法及区别的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
处理@PathVariable注解允许参数为空、允许不传参数的问题
这篇文章主要介绍了处理@PathVariable注解允许参数为空、允许不传参数的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-23