一个不错的命令行解析类

原文链接:Command line parser



 作者所考虑的语法是:
CommandLine::=[<Key> [,<Key>]]
<Key>::=<Delimeter>KeyName[<Separator><Value>]
<Value> ::= { KeyValue | <QuoteChar>Quoted Key Value<QuoteChar>} ][
<Delimeter>::= - | / }
<Separator>::= { : }
<QuoteChar>::= " }



typedef CString CCmdLineParser_String ;

#include 
<map>
using std::map;


class CCmdLineParser 
{
public:
    
class CValsMap : public map<CCmdLineParser_String, CCmdLineParser_String> {};//存储关键字--值对
    typedef CValsMap::const_iterator POSITION;//迭代器
public:
    CCmdLineParser(LPCTSTR sCmdLine 
= NULL, bool bCaseSensitive = false);//默认大小写不敏感
    virtual ~CCmdLineParser();

    
bool Parse(LPCTSTR sCmdLine);//解析命令行

    LPCTSTR getCmdLine() 
const return m_sCmdLine; }

    
void setCaseSensitive(bool bSensitive) { m_bCaseSensitive = bSensitive; }
    
bool getCaseSensitive() const return m_bCaseSensitive; }

    
const CValsMap& getVals() const return m_ValsMap; }

    
// Start iterating through keys and values
    POSITION getFirst() const;//第一个
    
// Get next key-value pair, returns empty sKey if end reached
    POSITION getNext(POSITION& pos, CCmdLineParser_String& sKey, CCmdLineParser_String& sValue) const;//迭代器往后
    
// just helper ;)
    bool isLast(POSITION& pos) const;//是否是最后一个

    
// TRUE if "Key" present in command line
    bool HasKey(LPCTSTR sKey) const;//是否包含指定关键字
    
// Is "key" present in command line and have some value
    bool HasVal(LPCTSTR sKey) const;//是否包含指定值
    
// Returns value if value was found or NULL otherwise
    LPCTSTR GetVal(LPCTSTR sKey) const;//获取值
    
// Returns true if value was found
    bool GetVal(LPCTSTR sKey, CCmdLineParser_String& sValue) const;

private:
    CValsMap::const_iterator findKey(LPCTSTR sKey) 
const;//查找指定关键字
private:
    CCmdLineParser_String m_sCmdLine;
    CValsMap    m_ValsMap;
    
bool m_bCaseSensitive;

    
static const TCHAR m_sDelimeters[];
    
static const TCHAR m_sValueSep[];
    
static const TCHAR m_sQuotes[];
}
;

const TCHAR CCmdLineParser::m_sDelimeters[] = _T("-/");//键的起始符
const TCHAR CCmdLineParser::m_sQuotes[] = _T("\"");    // Can be _T("\"\'"),  for instance
const TCHAR CCmdLineParser::m_sValueSep[] = _T(" :"); // Space MUST be in set 键值分隔符

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCmdLineParser::CCmdLineParser(LPCTSTR sCmdLine, 
bool bCaseSensitive)
: m_bCaseSensitive(bCaseSensitive)
{
    
if(sCmdLine) 
    
{
        Parse(sCmdLine);
    }

}


CCmdLineParser::
~CCmdLineParser()
{
    m_ValsMap.clear();
}


bool CCmdLineParser::Parse(LPCTSTR sCmdLine) 
{
    
if(!sCmdLine) return false;
    
    m_sCmdLine 
= sCmdLine;
    m_ValsMap.clear();
    
const CCmdLineParser_String sEmpty;

    
int nArgs = 0;
    LPCTSTR sCurrent 
= sCmdLine;
    
while(true{
        
// /Key:"arg"
        if(_tcslen(sCurrent) == 0break; } // No data left
        LPCTSTR sArg = _tcspbrk(sCurrent, m_sDelimeters);
        
if(!sArg) break// No delimeters found
        sArg =  _tcsinc(sArg);
        
// Key:"arg"
        if(_tcslen(sArg) == 0break// String ends with delimeter
        LPCTSTR sVal = _tcspbrk(sArg, m_sValueSep);
        
if(sVal == NULL) //Key ends command line
            CCmdLineParser_String csKey(sArg);
            
if(!m_bCaseSensitive) {
                csKey.MakeLower();
            }

            m_ValsMap.insert(CValsMap::value_type(csKey, sEmpty));
            
break;
        }
 else if(sVal[0== _T(' '|| _tcslen(sVal) == 1 ) // Key with no value or cmdline ends with /Key:
            CCmdLineParser_String csKey(sArg, sVal - sArg);
            
if(!csKey.IsEmpty()) // Prevent /: case
                if(!m_bCaseSensitive) {
                    csKey.MakeLower();
                }

                m_ValsMap.insert(CValsMap::value_type(csKey, sEmpty));
            }

            sCurrent 
= _tcsinc(sVal);
            
continue;
        }
 else // Key with value
            CCmdLineParser_String csKey(sArg, sVal - sArg);
            
if(!m_bCaseSensitive) {
                csKey.MakeLower();
            }


            sVal 
= _tcsinc(sVal);
            
// "arg"
            LPCTSTR sQuote = _tcspbrk(sVal, m_sQuotes), sEndQuote(NULL);
            
if(sQuote == sVal) // Quoted String
                sQuote = _tcsinc(sVal);
                sEndQuote 
= _tcspbrk(sQuote, m_sQuotes);
            }
 else {
                sQuote 
= sVal;
                sEndQuote 
= _tcschr(sQuote, _T(' '));
            }


            
if(sEndQuote == NULL) // No end quotes or terminating space, take rest of string
                CCmdLineParser_String csVal(sQuote);
                
if(!csKey.IsEmpty()) // Prevent /:val case
                    m_ValsMap.insert(CValsMap::value_type(csKey, csVal));//保存
                }

                
break;
            }
 else // End quote or space present
                if(!csKey.IsEmpty()) {    // Prevent /:"val" case
                    CCmdLineParser_String csVal(sQuote, sEndQuote - sQuote);
                    m_ValsMap.insert(CValsMap::value_type(csKey, csVal));
                }

                sCurrent 
= _tcsinc(sEndQuote);
                
continue;
            }

        }


    }

    
    
return (nArgs > 0);
}


CCmdLineParser::CValsMap::const_iterator CCmdLineParser::findKey(LPCTSTR sKey) 
const 
{
    CCmdLineParser_String s(sKey);
    
if(!m_bCaseSensitive) {
        s.MakeLower();
    }

    
return m_ValsMap.find(s);
}

// TRUE if "Key" present in command line
bool CCmdLineParser::HasKey(LPCTSTR sKey) const 
{
    CValsMap::const_iterator it 
= findKey(sKey);
    
if(it == m_ValsMap.end()) return false;
    
return true;
}


// Is "key" present in command line and have some value
bool CCmdLineParser::HasVal(LPCTSTR sKey) const 
{
    CValsMap::const_iterator it 
= findKey(sKey);
    
if(it == m_ValsMap.end()) return false;
    
if(it->second.IsEmpty()) return false;
    
return true;
}

// Returns value if value was found or NULL otherwise
LPCTSTR CCmdLineParser::GetVal(LPCTSTR sKey) const 
{
    CValsMap::const_iterator it 
= findKey(sKey);
    
if(it == m_ValsMap.end()) return false;
    
return LPCTSTR(it->second);
}

// Returns true if value was found
bool CCmdLineParser::GetVal(LPCTSTR sKey, CCmdLineParser_String& sValue) const 
{
    CValsMap::const_iterator it 
= findKey(sKey);
    
if(it == m_ValsMap.end()) return false;
    sValue 
= it->second;
    
return true;
}


CCmdLineParser::POSITION CCmdLineParser::getFirst() 
const 
{
    
return m_ValsMap.begin();
}

CCmdLineParser::POSITION CCmdLineParser::getNext(POSITION
& pos, CCmdLineParser_String& sKey, CCmdLineParser_String& sValue) const 
{
    
if(isLast(pos)) {
        sKey.Empty();
        
return pos;
    }
 else {
        sKey 
= pos->first;
        sValue 
= pos->second;
        pos 
++;
        
return pos;
    }

}

// just helper ;)
bool CCmdLineParser::isLast(POSITION& pos) const
{
    
return (pos == m_ValsMap.end());
}



#include "stdafx.h"
#include 
"cmdlineparser.h"

int main(int argc, char* argv[])
{
    CCmdLineParser parser(_T(
"/Key1 /Key2: -Key3:Val3 -Key4:\"Val 4-with/spaces/and-delimeters\" /Key5:Val5"));

    ASSERT(parser.HasKey(_T(
"Key1")) == true);
    ASSERT(parser.HasKey(_T(
"Key10")) == false);
    ASSERT(parser.HasVal(_T(
"Key2")) == false);
    ASSERT(parser.HasKey(_T(
"Key5"))==true);
    _tprintf(_T(
"==================== Test Parser ====================\n"));
    _tprintf(_T(
"Command line: [%s]\n"), parser.getCmdLine());//获取命令行参数
    _tprintf(_T("Key1 has value: [%s]\n"), parser.GetVal(_T("Key1")));// -> []; //(empty string)
    _tprintf(_T("Key2 has value: [%s]\n"), parser.GetVal(_T("Key2")));// -> []; 
    _tprintf(_T("Key3 has value: [%s]\n"), parser.GetVal(_T("Key3")));// -> [Val3];
    _tprintf(_T("Key4 has value: [%s]\n"), parser.GetVal(_T("Key4")));// -> [Val 4-with/spaces/and-delimeters];
    _tprintf(_T("Key5 has value: [%s]\n"), parser.GetVal(_T("Key5")));// -> []; //(empty string)

    _tprintf(_T(
"\n================= Real Command Line =================\n"));
    CCmdLineParser realParser(::GetCommandLine());
    CCmdLineParser::POSITION pos 
= realParser.getFirst();    
    CString sKey, sVal;
    
while(!realParser.isLast(pos)) 
    
{
        realParser.getNext(pos, sKey, sVal);
        _tprintf(_T(
"Key: [%s], Val: [%s]\n"), sKey, sVal);
    }

    system(
"pause");
    
return 0;
}

posted on 2008-06-28 15:16  Phinecos(洞庭散人)  阅读(1839)  评论(0编辑  收藏  举报

导航