作者:淡月清风 日期:2009-05-26
正则表达式是最强大的文本解析工具之一,
在ATL中
也
提供了一些用于正则表达式的类库(CATLRegExp等),本文将简要说明这些类库的使用方法。
1.CATLRegExp
类
声明:
template <class CharTraits=CAtlRECharTraits>
class
CAtlRegExp;
初始化:
与微软的
GRETA
类库(微软研究院推出的另一个正则表达式类库)不同,
CATLRegExp
并没有在构造函数中提供初始化匹配字符串的方法,而是让使用者通过调用它的
Parse()
方法,使用正则表达式字符串作为参数,就可以构造出一个我们所需要的用于匹配的类,例如我们需要匹配一种时间格式,可以是
h:mm
,也可以是
hh:mm
,那么我们可以这样构造我们的
CAtlRegExp
类:
CAtlRegExp <> re;
re.Parse( "{[0-9]?[0-9]}:{[0-9][0-9]}" );
ATL
的正则表达式语法和
Perl
的正则表达式语法大同小异,不过有一个值得注意的地方就是
ATL
中用大括号(
{ }
)表示其匹配字符串中的
Group
,我们上面的表达式中,就声明了
2
个
Group
,一个是
[0-9]?[0-9]
,另一个是
[0-9][0-9]
。
匹配:
调用
CATLRegExp
的
Match()
方法,就可以用该类来进行匹配了,
Match
方法的原型如下:
BOOL
Match(const RECHAR *szIn,
CAtlREMatchContext
<
CharTraits
>
*pContext,
const
RECHAR **ppszEnd=NULL)
参数的含义很明显,不过需要注意到第一个参数的型别是:
const RECHAR * szIN
,是一个
const
指针,这表明我们可以方便得使用
std::string
类的
c_str()
方法给其传递参数。
Match
的结果通过第二个参数
pContext
所指向的
CAtlREMatchContext
< >
类来返回,
Match
的结果及其相关信息都被存放在
CAtlREMatchContext
类中,我们只要访问
CAtlREMatchContext
的方法和成员就可以得到匹配的结果。
2.CAtlREMatchContext
类
声明:
template <class CharTraits=CAtlRECharTraits>
class CAtlREMatchContext
使用:
CAtlREMatchContext
通过
m_uNumGroups
成员以及
GetMatch
()方法向调用者提供匹配的结果信息。
m_uNumGroups
代表匹配上的
Group
有多少组,
GetMatch()
则根据传递给它的
Group
的
Index
值,返回匹配上的字符串的
pStart
和
pEnd
指针,调用者有了这两个指针,自然可以很方便的得到匹配结果。
3.
一个小示例
下面这个例子来源于
MSDN
,演示了
CATLRegExp
和
CAtlREMatchContext
类的典型使用方法:
#include
"stdafx.h"
#include
<atlrx.h>
int
main(int argc, char* argv[])
{
CAtlRegExp<> reUrl;
// five match groups: scheme, authority, path, query, fragment
REParseError status = reUrl.Parse(
"({[^:/?#]+}:)?(//{[^/?#]*})?{[^?#]*}(?{[^#]*})?(#{.*})?" );
if (REPARSE_ERROR_OK != status)
{
// Unexpected error.
return 0;
}
CAtlREMatchContext<> mcUrl;
if (!reUrl.Match(
"http://search.microsoft.com/us/Search.asp?qu=atl&boolean=ALL#results",
&mcUrl))
{
// Unexpected error.
return 0;
}
for (UINT nGroupIndex = 0; nGroupIndex < mcUrl.m_uNumGroups;
++nGroupIndex)
{
const CAtlREMatchContext<>::RECHAR* szStart = 0;
const CAtlREMatchContext<>::RECHAR* szEnd = 0;
mcUrl.GetMatch(nGroupIndex, &szStart, &szEnd);
ptrdiff_t nLength = szEnd - szStart;
printf("%d: /"%.*s/"/n", nGroupIndex, nLength, szStart);
}
}
输出
:
0: "http"
1: "search.microsoft.com"
2: "/us/Search.asp"
3: "qu=atl&boolean=ALL"
4: "results"
例子中所用的正则表达式为:
({[^:/?#]+}:)?(//{[^/?#]*})?{[^?#]*}(?{[^#]*})?(#{.*})?
以
()
为分界标志,共分成
5
组,第一组是
{[^:/?#]+}:
,
^
是
“
非
”
后面成员的意思,那么也就是说第一组从开头开始,一直到
:
、
/
、
?
、
#
其中任何一个结束。联系后面的待匹配字符串就可以得出所匹配的结果是
http
。
4.
自定义匹配字符串的缩写形式
为了方便,
ATL
已经帮我们定义了一些经常用到的正则表达式的简略形式。例如:
/d
代表
([0-9])
、
/n
代表
(/r|(/r?/n))
等。这些缩写形式都体现在
CAtlRECharTraitsA/CAtlRECharTraitsW
等类中,把这些类作为模板参数传递给
CATLRegExp
和
CAtlREMatchContext
,我们就可以定义自己的匹配字符串缩写了。
class
CAtlRECharTraitsA
{
static const RECHARTYPE** GetAbbrevs()
{
static const RECHARTYPE *s_szAbbrevs[] =
{
"a([a-zA-Z0-9])", // alpha numeric
"b([ //t])", // white space (blank)
"c([a-zA-Z])", // alpha
"d([0-9])", // digit
"h([0-9a-fA-F])", // hex digit
"n(/r|(/r?/n))", // newline
"q(/"[^/"]*/")|(/'[^/']*/')", // quoted string
"w([a-zA-Z]+)", // simple word
"z([0-9]+)", // integer
NULL
};
return s_szAbbrevs;
}
};
以上是
atlrx.h
摘录下来的代码,可以很清楚地看到
ATL
是通过一个
GetAbbrevs
()
函数来定义字符串缩写的。要定义新的缩写形式,我们只需要这样:
Class
MyRegTraits : public ATL::CAtlRECharTraitsA
{
public
:
static const RECHARTYPE** GetAbbrevs()
{
static const RECHARTYPE *s_szAbbrevs[] =
{
"a([a-zA-Z0-9])", // alpha numeric
"b([ //t])", // white space (blank)
"c([a-zA-Z])", // alpha
"d([0-9])", // digit
"h([0-9a-fA-F])", // hex digit
"n(/r|(/r?/n))", // newline
"q(/"[^/"]*/")|(/'[^/']*/')", // quoted string
"w([a-zA-Z]+)", // simple word
"z([0-9]+)", // integer
"e([0-8]+)", //
自己添加
NULL
};
return s_szAbbrevs;
}
};
让我们自己定义的
Trait
类继承自
CAtlRECharTraitsA
,然后改写
GetAbbrevs()
函数,增加一些需要的简写就可以被使用了。下面的代码示例了使用了我们自己的类中定义的
“/e”
简略表达:
int
main ( )
{
ATL::CAtlRegExp < MyRegTraits > re ;
re.Parse( "//e+" );
ATL::CAtlREMatchContext < MyRegTraits > mc;
BOOL res1 = re.Match( "678", &mc ); // returns TRUE: successful match
res1 = re.Match ( "999" , &mc ) ; // returns FALSE
:
match fail
}
只要在构造 ATL::CAtlRegExp 和 ATL::CAtlREMatchContext 类时,传递过去我们的 MyRegTraits 类作为 Traits 的参数,就可以直接使用自己定义的简略符号了。
5.CAtlRegExp对中文的支持
在CAtlRegExp中,默认使用CAtlRECharTraits,实际上是CAtlRECharTraitsA
要支持ANSI模式下的中文,必须使用CAtlRECharTraitsMB,见如下代码:
注意要包含#include <atlrx.h>。
要支持ANSI模式下的中文,必须使用CAtlRECharTraitsMB,见如下代码:
注意要包含#include <atlrx.h>。
char* szText="测试一下地址dgx_lsyd3@163.com看看/r/n";
//匹配电子邮件地址的正则表达式
char
*
szRegExpEmail="({[a-zA-Z0-9_/.]+@[a-zA-Z0-9]+[/.][a-zA-Z0-9]+[/.]?[a-zA-Z0-9]+})";
CAtlRegExp
<
CAtlRECharTraitsMB
>
reEmail;
REParseError
reError=reEmail.Parse((const ATL::CAtlRegExp<CAtlRECharTraitsMB>::RECHAR *)szRegExpEmail);
if
(REPARSE_ERROR_OK != reError)
return;
CAtlREMatchContext
<
CAtlRECharTraitsMB
>
mcEmail;
if
(!reEmail.Match((const ATL::CAtlRegExp<CAtlRECharTraitsMB>::RECHAR *)szText,&mcEmail))
{
return;
}
char
szBuf[260];
for
(UINT nGroupIndex = 0; nGroupIndex < mcEmail.m_uNumGroups;++nGroupIndex)
{
const CAtlREMatchContext<CAtlRECharTraitsMB>::RECHAR* szStart = 0;
const CAtlREMatchContext<CAtlRECharTraitsMB>::RECHAR* szEnd = 0;
mcEmail.GetMatch(nGroupIndex, &szStart, &szEnd);
memcpy(szBuf,szStart,szEnd-szStart);
szBuf[szEnd-szStart]=0;
printf("%s/n",szBuf);
}
输出:
dgx_lsyd3@163.com
dgx_lsyd3@163.com
6.
结尾
虽然现在
C++
的社区里已经拥有了
Boost::regex
,
GRETA
等非常著名的正则表达式库,可是作为
VC++
自带的模板库,
ATL
中的正则表达式库仍然给我们的工作提供了极大的便利。由于
ATL
是微软官方发布的
Library
,所以它拥有良好的文档说明、严格的测试以及微软官方的技术支持。另外在用
ATL
开发
COM
组件的时候,更可以方便地利用正则库的巨大威力。
原文:
1.http://blog.donews.com/crackme/archive/2006/04/26/847531.aspx
2.http://www.vckbase.com/document/viewdoc/?id=1256
在MSDN中:ms-help://MS.MSDNQTR.2003FEB.2052/vclib/html/vclrfCAtlRegExp.htm
其他参考:http://www.codeproject.com/KB/string/mfcregex.aspx?df=100&forumid=276265&exp=0&select=1541164