GRETA正则表达式模板类库

本文摘要翻译了几篇文章的内容,简单介绍 ATL CAtlRegExpGRETABoost::regex 等正则表达式库,这些表达式库使我们可以方便地利用正则库的巨大威力,给我们的工作提供了便利。

正则表达式语法

字符元

意义

.

匹配单个字符

[ ]

指定一个字符类,匹配方括号内的任意字符。例:[abc] 匹配 "a", "b" "c"

^

如果^出现在字符类的开始处,它否定了字符类,这个被否定的字符类匹配除却方括号内的字符的字符。如:[^abc]匹配除了"a", "b""c"之外的字符。如果^出现在正则表达式前边,它匹配输入的开头,例:^[abc]匹配以"a", "b""c"开头的输入。

-

在字符类中,指定一个字符的范围。例如:[0-9]匹配"0""9"的数字。

?

指明?前的表达式是可选的,它可以匹配一次或不进行匹配。例如: [0-9][0-9]? 匹配"2""12"

+

指明?前的表达式匹配一次或多次。例如:[0-9]+匹配"1", "13", "666"等。

*

指明*前的表达式匹配零次或多次。

??, +?, *?

?, +*的非贪婪匹配版本,它们尽可能匹配较少的字符;而?, +*则是贪婪版本,尽可能匹配较多的字符。例如:输入"<abc><def>", <.*?> 匹配"<abc>",而<.*>匹配"<abc><def>"

( )

 分组操作符。例如:(/d+,)*/d+匹配一串由逗号分开的数字,例如: "1""1,23,456"

/

转义字符,转义紧跟的字符。例如,[0-9]+ 匹配一个或多个数字,而 [0-9]/+ 匹配一个数字后跟随一个加号的情况。反斜杠/也用于表示缩写,/a 就表示任何数字、字母。如果/后紧跟一个数字n,则它匹配第n个匹配群组(0开始),例如,<{.*?}>.*?<//0>匹配"<head>Contents</head>"。注意,在C++字符串中,反斜杠/需要用双反斜杠//来表示: "//+", "//a", "<{.*?}>.*?<///0>"

$

放在正则表达式的最后,它匹配输入的末端。例如:[0-9]$匹配输入的最后一个数字。

|

间隔符,分隔两个表达式,以正确匹配其中一个,例如:T|the匹配"The" "the"


 


缩写匹配

缩写

匹配

/a

字母、数字([a-zA-Z0-9])

/b

空格(blank): ([ //t])

/c

字母([a-zA-Z])

/d

十进制数 ([0-9])

/h

十六进制数([0 -9a -fA-F])

/n

换行: (/r|(/r?/n))

/q

引用字符串(/"[^/"]*/")|(/''''[^/'''']*/'''')

/w

一段文字 ([a-zA-Z]+)

/z

一个整数([0-9]+)


ATL CATLRegExp
  ATL Server常常需要对地址、命令等复杂文字字段信息解码,而正则表达式是强大的文字解析工具,所以,ATL提供了正则表达式解释工具。
示例:

#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"

  Match的结果通过第二个参数pContext所指向的CAtlREMatchContext类来返回,Match的结果及其相关信息都被存放在CAtlREMatchContext类中,只要访问CAtlREMatchContext的方法和成员就可以得到匹配的结果。CAtlREMatchContext通过m_uNumGroups成员以及GetMatch()方法向调用者提供匹配的结果信息。m_uNumGroups代表匹配上的Group有多少组,GetMatch()则根据传递给它的GroupIndex值,返回匹配上的字符串的pStartpEnd指针,调用者有了这两个指针,自然可以很方便的得到匹配结果。

更多内容请参阅: CAtlRegExp Class

GRETA
  GRETA是微软研究院推出的一个正则表达式模板类库,GRETA 包含的 C++ 对象和函数,使字符串的模式匹配和替换变得很容易,它们是:

·   " rpattern: 搜索的模式

·   " match_results/subst_results: 放置匹配、替换结果的容器

  为了执行搜索和替换的操作,用户首先需要用一个描述匹配规则的字符串来显式初始化一个rpattern对象,然后把需要匹配的字符串作为参数,调用rpattern的函数,比如match()或者substitute(),就可以得到匹配后的结果。如果match()/substitute()调用失败,函数返回false,如果调用成功,函数返回true,此时,match_results对象存储了匹配结果。请看例子代码:

#include <iostream>

#include <string>

#include "regexpr2.h"

using namespace std;

using namespace regex;

int main() {

    match_results results;

    string str( "The book cost $12.34" );

    rpattern pat( "//$(//d+)(//.(//d//d))?" ); 

    // Match a dollar sign followed by one or more digits,

    // optionally followed by a period and two more digits.

    // The double-escapes are necessary to satisfy the compiler.

    match_results::backref_type br = pat.match( str, results );

    if( br.matched ) {

        cout << "match success!" << endl;

        cout << "price: " << br << endl;

    } else {

        cout << "match failed!" << endl;

    }

    return 0;

}     

程序输出将是:

match success!

price: $12.34

  您可以阅读GRETA文档,获知rpattern对象的细节内容,并掌握如何自定义搜索策略来得到更好的效率。
  注意:所有在头文件regexpr2.h里的声明都在名称空间regex之中,用户使用其中的对象和函数时,必须加上前缀"regex::",或者预先"using namespace regex;" 一下,为了简单起见,下文的示例代码中将省略"regex::" 前缀。 作者生成了greta.libregexpr2.h文件,只需这两个文件的支持即可使用greta来解析正则表达式。


匹配速度小议
  不同的正则表达式匹配引擎擅长于不同匹配模式。作为一个基准,当用模式:"^([0-9]+)(/-| |$)(.*)$" 匹配字符串"100- this is a line of ftp response which contains a message string"时,GRETA的匹配速度比boost(http://www.boost.org)正则表达式库大约快7倍,比ATL7CATLRegExp10倍之多! Boost Regex 的说明文档带有一个很多模式的匹配测试Performance结果。比较这个结果后,我发现GRETA在大部分情况下和Boost Regex性能差不多,但是在用Visual Studio.Net 2003编译的情况下,GRETA还略胜一筹。

Boost.Regex

  Boost提供了boost::basic_regex来支持正则表达式。boost::basic_regex的设计非常类似std::basic_string

namespace boost{

template <class charT,

       class traits = regex_traits<charT>,

       class Allocator = std::allocator<charT> > class basic_regex;

typedef basic_regex<char> regex;

typedef basic_regex<wchar_t> wregex;

}     

  Boost Regex 库附带的文档非常丰富,示例更是精彩,比如有两个例子程序,不多的代码,程序就可以直接对 C++ 文件进行语法高亮标记,生成相应的 HTML (converts a C++ file to syntax highlighted HTML)。下面的例子可以分割一个字符串到一串标记符号(split a string into tokens)

#include <list>

#include <boost/regex.hpp>

unsigned tokenise(std::list<std::string>& l, std::string& s)

{

   return boost::regex_split(std::back_inserter(l), s);

}

 

#include <iostream>

using namespace std;

#if defined(BOOST_MSVC) || (defined(__BORLANDC__) && (__BORLANDC__ == 0x550))

// problem with std::getline under MSVC6sp3

istream& getline(istream& is, std::string& s)

{

   s.erase();

   char c = is.get();

   while(c != ''''/n'''')

   {

      s.append(1, c);

      c = is.get();

   }

   return is;

}

#endif

int main(int argc)

{

   string s;

   list<string> l;

   do{

      if(argc == 1)

      {

         cout << "Enter text to split (or /"quit/" to exit): ";

         getline(cin, s);

         if(s == "quit") break;

      }

      else

         s = "This is a string of tokens";

      unsigned result = tokenise(l, s);

      cout << result << " tokens found" << endl;

      cout << "The remaining text is: /"" << s << "/"" << endl;

      while(l.size())

      {

         s = *(l.begin());

         l.pop_front();

         cout << s << endl;

      }

   }while(argc == 1);

   return 0;

}


http://topic.csdn.net/t/20040818/10/3285376.html

ASP.NET   完全支持正规表达式的处理。正规表达式提供了一种高级的,但不直观的字符串匹配和处理的方法。用过正规表达式的  
 
朋友都知道,正规表达式的功能非常强大,但学起来不是那么容易。    
   
 
比如:    
   
  ^.+@.+//..+$    
   
 
这段有效却难以理解的代码足够使一些程序员头痛(我就是)或者让他们放弃使用正规表达式。相信当你读完这个教程后,就可  
 
以理解这段代码的含义了。  
   
 
基本模式匹配  
   
 
一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符  
 
串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:  
   
  ^once    
   
 
这个模式包含一个特殊的字符^,表示该模式只匹配那些以once开头的字符串。例如该模式与字符串"once   upon   a   time"匹配,  
 
"There   once   was   a   man   from   NewYork"不匹配。正如如^符号表示开头一样,$符号用来匹配那些以给定模式结尾的字符串。  
   
  bucket$    
   
 
这个模式与"Who   kept   all   of   this   cash   in   a   bucket"匹配,与"buckets"不匹配。字符^$同时使用时,表示精确匹配(字符串与模式一  
 
样)。例如:  
   
  ^bucket$    
   
 
只匹配字符串"bucket"。如果一个模式不包括^$,那么它与任何包含该模式的字符串匹配。例如:模式  
   
  once    
   
 
与字符串  
   
  There   once   was   a   man   from   NewYork  
  Who   kept   all   of   his   cash   in   a   bucket.  
   
 
是匹配的。  
   
 
在该模式中的字母(o-n-c-e)是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点  
 
符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠(/)打头。制表符的转义序列是:/t。所以如果我  
 
们要检测一个字符串是否以制表符开头,可以用这个模式:  
   
  ^/t    
   
 
类似的,用/n表示新行/r表示回车。其他的特殊符号,可以用在前面加上反斜杠,如反斜杠本身用//表示,句号./.表示,以  
 
此类推。  
   
 
字符簇  
   
 
INTERNET的程序中,正规表达式通常用来验证用户的输入。当用户提交一个FORM以后,要判断输入的电话号码、地址、  
  EMAIL
地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。  
   
 
所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符  
 
放在一个方括号里:  
   
  [AaEeIiOoUu]    
   
 
这个模式与任何元音字符匹配,但只能表示一个字符。用连字号可以表示一个字符的范围,如:  
   
  [a-z]   //
匹配所有的小写字母    
  [A-Z]   //
匹配所有的大写字母    
  [a-zA-Z]   //
匹配所有的字母    
  [0-9]   //
匹配所有的数字    
  [0-9/./-]   //
匹配所有的数字,句号和减号    
  [   /f/r/t/n]   //
匹配所有的白字符    
   
 
同样的,这些也只表示一个字符,这是一个非常重要的。如果要匹配一个由一个小写字母和一位数字组成的字符串,比  
 
"z2""t6""g7",但不是"ab2""r2d3"   "b52"的话,用这个模式:  
   
  ^[a-z][0-9]$    
   
 
尽管[a-z]代表26个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。  
   
 
前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一组方括号里使用^是,它表示排除的意思,常常用来剔  
 
除某个字符。还用前面的例子,我们要求第一个字符不能是数字:  
   
  ^[^0-9][0-9]$    
   
 
这个模式与"&5""g7""-2"是匹配的,但与"12""66"是不匹配的。下面是几个排除特定字符的例子:  
   
  [^a-z]   //
除了小写字母以外的所有字符    
  [^/^]   //
除了(/)(/)(^)之外的所有字符    
  [^/"/']   //
除了双引号(")和单引号(')之外的所有字符    
   
   
 
特殊字符"."   (点,句号)在正规表达式中用来表示除了新行之外的所有字符。所以模式"^.5$"与任何两个字符的、以数字5结尾和以  
 
其他非新行字符开头的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一个新行的字符串。  
   
  PHP
的正规表达式有一些内置的通用字符簇,列表如下:  
   
 
字符簇   含义    
  [[:alpha:]]  
任何字母    
  [[:digit:]]  
任何数字    
  [[:alnum:]]  
任何字母和数字    
  [[:space:]]  
任何白字符    
  [[:upper:]]  
任何大写字母    
  [[:lower:]]  
任何小写字母    
  [[:punct:]]  
任何标点符号    
  [[:xdigit:]]  
任何16进制的数字,相当于[0 -9a -fA-F]    
 
确定重复出现  
   
 
到现在为止,你已经知道如何去匹配一个字母或数字,但更多的情况下,可能要匹配一个单词或一组数字。一个单词有若干个字  
 
母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数。    
   
 
字符簇   含义    
  ^[a-zA-Z_]$  
所有的字母和下划线    
  ^[[:alpha:]]{3}$  
所有的3个字母的单词    
  ^a$  
字母a    
  ^a{4}$   aaaa    
  ^a{2,4}$   aa,aaa
aaaa    
  ^a{1,3}$   a,aa
aaa    
  ^a{2,}$  
包含多于两个a的字符串    
  ^a{2,}  
如:aardvarkaaab,但apple不行    
  a{2,}  
如:baadaaa,但Nantucket不行    
  /t{2}  
两个制表符    
  .{2}  
所有的两个字符    
   
 
这些例子描述了花括号的三种不同的用法。一个数字,{x}的意思是前面的字符或字符簇只出现x;一个数字加逗号,{x,}的意  
 
思是前面的内容出现x或更多的次数;两个用逗号分隔的数字,{x,y}表示前面的内容至少出现x次,但不超过y。我们可以把  
 
模式扩展到更多的单词或数字:  
   
  ^[a-zA-Z0-9_]{1,}$   //
所有包含一个以上的字母、数字或下划线的字符串    
  ^[0-9]{1,}$   //
所有的正数    
  ^/-{0,1}[0-9]{1,}$   //
所有的整数    
  ^/-{0,1}[0-9]{0,}/.{0,1}[0-9]{0,}$   //
所有的小数    
   
 
最后一个例子不太好理解,是吗?这么看吧:与所有以一个可选的负号(/-{0,1})开头(^)、跟着0个或更多的数字([0-9]{0,})、和一个  
 
可选的小数点(/.{0,1})再跟上0个或多个数字([0-9]{0,}),并且没有其他任何东西($)。下面你将知道能够使用的更为简单的方法。  
   
 
特殊字符"?"{0,1}是相等的,它们都代表着:“0个或1个前面的内容前面的内容是可选的。所以刚才的例子可以简化为:  
   
  ^/-?[0-9]{0,}/.?[0-9]{0,}$    
   
 
特殊字符"*"{0,}是相等的,它们都代表着“0个或多个前面的内容。最后,字符"+"   {1,}是相等的,表示“1个或多个前面的内  
 
,所以上面的4个例子可以写成:  
   
  ^[a-zA-Z0-9_]+$   //
所有包含一个以上的字母、数字或下划线的字符串    
  ^[0-9]+$   //
所有的正数    
  ^/-?[0-9]+$   //
所有的整数    
  ^/-?[0-9]*/.?[0-9]*$   //
所有的小数    
   
 
当然这并不能从技术上降低正规表达式的复杂性,但可以使它们更容易阅读。


BOOL CErrAnalyzer::IsExistErr()

{

    if(m_pStream == NULL)

    {

        cout<<"File not open"<<endl;

        return FALSE;

    }

 

    CAtlRegExp<> reUrl;

    REParseError status = reUrl.Parse(REGEX_PROJECTNAME);

    if (REPARSE_ERROR_OK != status)

    {

        cout<<"Parse error."<<endl;

        return FALSE;

    }

    CString bufRead;

    while(ReadString(bufRead) != FALSE)

    {

        CAtlREMatchContext<> mcUrl;

        mcUrl.m_uNumGroups = 0;

 

        if (!reUrl.Match(bufRead, &mcUrl))

        {

            continue;

        }

 

        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);

        }

        break;

    }

    return TRUE;

}

 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值