posts - 274,  comments - 1258,  trackbacks - 0

GRETA正则表达式模板类库


编译:胡金山

下载源代码

  本文摘要翻译了几篇文章的内容,简单介绍 ATL CAtlRegExp,GRETA,Boost::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()则根据传递给它的Group的Index值,返回匹配上的字符串的pStart和pEnd指针,调用者有了这两个指针,自然可以很方便的得到匹配结果。

更多内容请参阅: 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.lib和regexpr2.h文件,只需这两个文件的支持即可使用greta来解析正则表达式。

    匹配速度小议
      不同的正则表达式匹配引擎擅长于不同匹配模式。作为一个基准,当用模式:"^([0-9]+)(\-| |$)(.*)$" 匹配字符串"100- this is a line of ftp response which contains a message string"时,GRETA的匹配速度比boost(http://www.boost.org)正则表达式库大约快7倍,比ATL7的CATLRegExp快10倍之多! 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;
    }




    最新评论 [发表评论] [文章投稿] 查看所有评论 推荐给好友 打印

    胡先生辛辛苦苦将 greta 整理成为 lib 文件,实际上帮了大家一个倒忙。当使用在 UNICODE 版本下,或者使用在 dll 中的时候,都会产生错误。

    详细原因,请参考:
    http://www29.websamba.com/sswater/zh/greta/

    ( sswater 发表于 2005-10-11 9:40:00)
     
    用greta的lib文件link的时候有冲突 ( oyljerry 发表于 2004-11-19 21:10:00)
     
    ?? ?* ?+的地方还是没看明白,希望能详细解释一下 ( laomai 发表于 2004-10-10 10:04:00)
     
    而且从微软下载的包里并没有greta.lib文件阿? ( bluemonkey 发表于 2004-7-5 14:57:00)
     
    大哥,为什么我在VC 6里开了一个console项目,把GRETA的示例代码贴进去,link的时候会有如下这些错误阿?

    Linking...
    Reg_Express_try.obj : error LNK2001: unresolved external symbol "protected: void __thiscall regex::basic_rpattern_base<char const *,class regex::perl_syntax<char> >::_common_init(enum regex::REGEX_FLAGS)" (?_common_init@?$basic_rpattern_base@PBDV?$p
    erl_syntax@D@regex@@@regex@@IAEXW4REGEX_FLAGS@2@@Z)
    Reg_Express_try.obj : error LNK2001: unresolved external symbol "unsigned int __cdecl regex::detail::DEFAULT_BLOCK_SIZE(void)" (?DEFAULT_BLOCK_SIZE@detail@regex@@YAIXZ)
    Reg_Express_try.obj : error LNK2001: unresolved external symbol __resetstkoflw
    .
    .
    .

    Debug/Reg_Express_try.exe : fatal error LNK1120: 6 unresolved externals
    Error executing link.exe.

    Reg_Express_try.exe - 7 error(s), 0 warning(s)

    太长了贴不下了……

    ( bluemonkey 发表于 2004-7-5 14:55:00)
     
    用动态库调是好的 ( lpheni 发表于 2004-6-16 14:26:00)
     
    加倒程序中,也有和mc_一样的问题
    且 执行倒   rpattern pat( //"({[^:/?#]+}:)?(//{[^/?#]*})?{[^?#]*}(?{[^#]*})?(#{.*})?"
    "\\$(\\d+)(\\.(\\d\\d))?" 
    );  
    跟进去在头文件4061行:
    _common_init( this->m_flags );
    会死? ( lpheni 发表于 2004-6-16 10:18:00)
     
    to mc_
    关于C4786MSDN上说:
    Compiler Warning (level 1) C4786
    'identifier' : identifier was truncated to 'number' characters in the debug information

    The identifier string exceeded the maximum allowable length and was truncated.

    The debugger cannot debug code with symbols longer than 255 characters. In the debugger, you cannot view, evaluate, update, or watch the truncated symbols.

    This limitation can be overcome 
    由此来看它可能只是影响调试.
    可以使用
    ##pragma warning( disable : C4786)
    把这种警告全部屏蔽掉.
    关于Boost.Regex的例子
    boost本身提供了提供了大约有九个.可以直接研究之.
    目前我也是刚刚才看:) ( nscboy 发表于 2004-5-26 23:04:00)
     
    能不能多提供些 ATL CATLRegExp 和 Boost.Regex 的例子。 ( mc_ 发表于 2004-5-25 18:07:00)
     
    --------------------Configuration: test - Win32 Debug--------------------
    Compiling...
    test.cpp
    d:\program files\microsoft visual studio\vc98\include\xstring(133) : warning C4786: '?_Nil@?$_Tree@DU?$pair@$$CBDU?$charset_map_node@D@detail@regex@@@std@@U_Kfn@?$map@DU?$charset_map_node@D@detail@regex@@U?$less@D@std@@V?$allocator@U?$charset_map_no
    de@D@detail@regex@@@5@@2@U?$less@D@2@V?$allocator@U?$charset_map_node@D@detail@regex@@@2@@std@@1PAU_Node@12@A' : identifier was truncated to '255' characters in the browser information
    ..... ( mc_ 发表于 2004-5-25 8:04:00)
     

    ---
    本文章使用开源内容管理kicoy发布

    posted on 2006-06-12 12:11 踏雪赤兔 阅读(729) 评论(2)  编辑 收藏 引用
    只有注册用户登录后才能发表评论。

    百度空间| 见闻日记| 编程感悟
    我的twitter


    LOGO

    自我介绍:百度厂基础平台车间的一名挨踢民工。擅长C++、算法、语言设计、分布式计算,也用过Java,Python, PHP,JS/AS等语言开发。请关注我的twitter (免翻墙版) 发QQ消息


    添加到收藏夹 Locations of visitors to this page

    常用链接

    随笔分类(300)

    随笔档案(274)

    文章分类(38)

    相册

    收藏夹(54)

    与博主互动

    博客手拉手

    搜索

    •  

    积分与排名

    • 积分 - 392679
    • 排名 - 10

    最新评论

    阅读排行榜

    评论排行榜