C++ implements the generic parameter resolution class example

  • 2020-04-02 02:11:04
  • OfStack


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) //Dealing with empty strings
        {
            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 << " Parameter error " << 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 @  To parse the input parameters, pass first AddArgType Parameters will be required and allowed key Add to the decision list 
 *           through Parse In the result Returns the result of key For legal key . vecotr Is the parameter list 
 *           Parameter lists support the removal of quotes before and after parameters and the escape of quotes and 
 *
 *           Special legal field: 
 *           format                 Actual stored value 
 *          \value"            value"
 *          "\value""         value"
 *
 *           Notes: 
 *              1 , the parameters in the input parameter list are separated by Spaces 
 *              2 , -  After the single character keyword, -- Followed by a long string keyword 
 *              3 , keyword can not be repeated, long and short keywords can not appear in the parameter list at the same time, otherwise Parse The function prompts for an argument error 
 *
 *           Usage: 
 *              ParsingArgs pa;
 *              pa.AddArgType('l',"getlist", ParsingArgs::NO_VALUE); //The NO_VALUE keyword cannot be followed by an argument
 *              pa.AddArgType('p',"getuser", ParsingArgs::MAYBE_VALUE); //There may be a keyword after the MAYBE_VALUE keyword
 *              pa.AddArgType('o',"outFile", ParsingArgs::MUST_VALUE); //The MUST_VALUE keyword must be followed by an argument
 *              std::map<std::string, std::vector<std::string> > result;
 *              int iRet = pa.Parse(tmpPara,result); //Result stores a sequence of related values with the input keyword as the 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};
    
    bool AddArgType(const char shortName, const char * longName = NULL, KeyFlag flag=NO_VALUE);
    
    int Parse(const std::string & paras, std::map<std::string, std::vector<std::string> > & result, std::string &errPos);
private:
    
    KeyFlag GetKeyFlag(std::string &key);
    
    void RemoveKeyFlag(std::string & paras);
    
    bool GetWord(std::string & Paras, std::string & word);
    
    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; //Parameter information list
};
#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) //Returns the 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);
        }
    }
}

bool ParsingArgs::GetWord(std::string & Paras, std::string & word)
{
    size_t iNotSpacePos = Paras.find_first_not_of(' ',0);//Find the first non-space character position
    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
                    {//The last one is a space
                        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)
                { //Find the matching parentheses
                    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; //Keyword repetition
    }
    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; //Parameter identification
    std::string sKey = ""; //Key the keyword
    bool bFindValue = false; //Is there a value already
    while(!tmpString.empty())
    {
        std::string word = "";
        bool bRet = GetWord(tmpString, word);
        if(bRet == false)
        {
            errPos = tmpString;
            return -4;//Parameter parsing error
        }
        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;//No associated key was found
                            }
                        }
                        break;
                    case NO_VALUE:
                        errPos = tmpString;
                        return -2; //Options that cannot have arguments have arguments
                    default:
                        errPos = tmpString;
                        return -1;//Parameter error
                }//switch end
            }
        }
    }//while end
    return 0;
}


Related articles: