Phinecos(洞庭散人)
光荣在于平淡,艰巨因为漫长
一个不错的命令行解析类
原文链接:
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)
==
0
)
{
break
; }
//
No data left
LPCTSTR sArg
=
_tcspbrk(sCurrent, m_sDelimeters);
if
(
!
sArg)
break
;
//
No delimeters found
sArg
=
_tcsinc(sArg);
//
Key:"arg"
if
(_tcslen(sArg)
==
0
)
break
;
//
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(洞庭散人)
阅读(148)
评论(0)
编辑
收藏
网摘
所属分类:
C/C++/VC++