Chinaunix首页 | 论坛 | 博客
  • 博客访问: 451018
  • 博文数量: 145
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1060
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-22 11:52
个人简介

专注计算机技术: Linux Android 云计算 虚拟化 网络

文章分类

全部博文(145)

文章存档

2016年(3)

2015年(21)

2014年(75)

2013年(46)

我的朋友

分类: C/C++

2015-02-02 17:27:35

工作需要用到C++中的正则表达式,所以就研究了以上三种正则。

1.C regex

 

点击(此处)折叠或打开

  1. /* write by xingming
  2.  * time:2012年10月19日15:51:53
  3.  * for: test regex
  4.  * */

  5. #include <regex.h>
  6. #include <iostream>
  7. #include <sys/types.h>
  8. #include <stdio.h>
  9. #include <cstring>
  10. #include <sys/time.h>

  11. using namespace std;
  12. const int times = 1000000;

  13. int main(int argc,char** argv)
  14. {
  15.     char pattern[512]="finance\.sina\.cn|stock1\.sina\.cn|3g\.sina\.com\.cn.*(channel=finance|_finance$|ch=stock|/stock/)|dp.sina.cn/.*ch=9&";
  16.     const size_t nmatch = 10;
  17.     regmatch_t pm[10];
  18.     int z ;
  19.     regex_t reg;
  20.     char lbuf[256]="set",rbuf[256];
  21.     char buf[3][256] = {"finance.sina.cn/google.com/baidu.com.google.sina.cndddddddddddddddddddddda.sdfasdfeoasdfnahsfonadsdf",
  22.                     "3g.com.sina.cn.google.com.dddddddddddddddddddddddddddddddddddddddddddddddddddddbaidu.com.sina.egooooooooo",
  23.                     ""};
  24.     printf("input strings:\n");
  25.     timeval end,start;
  26.     gettimeofday(&start,NULL);
  27.     regcomp(&reg,pattern,REG_EXTENDED|REG_NOSUB);
  28.     for(int i = 0 ; i < times; ++i)
  29.     {
  30.         for(int j = 0 ; j < 3; ++j)
  31.         {
  32.             z = regexec(&reg,buf[j],nmatch,pm,REG_NOTBOL);
  33. /* if(z==REG_NOMATCH)
  34.                 printf("no match\n");
  35.             else
  36.                 printf("ok\n");
  37.                 */
  38.         }
  39.     }
  40.     gettimeofday(&end,NULL);
  41.     uint time = (end.tv_sec-start.tv_sec)*1000000 + end.tv_usec - start.tv_usec;
  42.     cout<<time/1000000<<" s and "<<time%1000000<<" us."<<endl;
  43.     return 0 ;
  44. }


使用正则表达式可简单的分成几步:

1.编译正则表达式

2.执行匹配

3.释放内存

首先,编译正则表达式

int regcomp(regex_t *preg, const char *regex, int cflags);

reqcomp()函数用于把正则表达式编译成某种格式,可以使后面的匹配更有效。

preg: regex_t结构体用于存放编译后的正则表达式;

regex: 指向正则表达式指针;

cflags:编译模式

共有如下四种编译模式:

REG_EXTENDED:使用功能更强大的扩展正则表达式

REG_ICASE:忽略大小写

REG_NOSUB:不用存储匹配后的结果

REG_NEWLINE:识别换行符,这样‘$’就可以从行尾开始匹配,‘^’就可以从行的开头开始匹配。否则忽略换行符,把整个文本串当做一个字符串处理。

其次,执行匹配

int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);

preg: 已编译的正则表达式指针;

string:目标字符串;

nmatch:pmatch数组的长度;

pmatch:结构体数组,存放匹配文本串的位置信息;

eflags:匹配模式

共两种匹配模式:

REG_NOTBOL:The match-beginning-of-line operator always fails to match  (but see  the  compilation  flag  REG_NEWLINE above). This flag may be used when different portions of a string are passed  to  regexec and the beginning of the string should not be interpreted as the beginning of the line.

REG_NOTEOL:The match-end-of-line operator always fails to  match  (but  see the compilation flag REG_NEWLINE above)

最后,释放内存
void regfree(regex_t *preg);
当使用完编译好的正则表达式后,或者需要重新编译其他正则表达式时,一定要使用这个函数清空该变量。


 其他,处理错误
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
当执行regcomp 或者regexec 产生错误的时候,就可以调用这个函数而返回一个包含错误信息的字符串。
errcode: 由regcomp 和 regexec 函数返回的错误代号。
preg: 已经用regcomp函数编译好的正则表达式,这个值可以为NULL。
errbuf: 指向用来存放错误信息的字符串的内存空间。
errbuf_size: 指明buffer的长度,如果这个错误信息的长度大于这个值,则regerror 函数会自动截断超出的字符串,但他仍然会返回完整的字符串的长度。所以我们可以用如下的方法先得到错误字符串的长度。

当然我在测试的时候用到的也比较简单,所以就直接用了,速度一会再说!

2,C++ regex

 

点击(此处)折叠或打开

  1. /* write by xingming
  2.  * time:2012年10月19日15:51:53
  3.  * for: test regex
  4.  * */

  5. #include <regex>
  6. #include <iostream>
  7. #include <stdio.h>
  8. #include <string>

  9. using namespace std;

  10. int main(int argc,char** argv)
  11. {
  12.     regex pattern("[[:digit:]]",regex_constants::extended);
  13.     printf("input strings:\n");
  14.     string buf;

  15.     while(cin>>buf)
  16.     {
  17.         printf("*******\n%s\n********\n",buf.c_str());

  18.         if(buf == "quit")
  19.         {
  20.             printf("quit just now!\n");
  21.             break;
  22.         }

  23.         match_results<string::const_iterator> result;
  24.         printf("run compare now! '%s'\n", buf.c_str());
  25.         bool valid = regex_match(buf,result,pattern);
  26.         printf("compare over now! '%s'\n", buf.c_str());

  27.         if(!valid)
  28.             printf("no match!\n");
  29.         else
  30.             printf("ok\n");
  31.     }

  32.     return 0 ;
  33. }

C++这个真心不想多说它,测试过程中发现 字符匹配的时候 ‘a' 是可以匹配的,a+也是可以的,[[:w:]]也可以匹配任意字符,但[[:w:]]+就只能匹配一个字符,+号貌似不起作用了。所以后来就干脆放弃了这伟大的C++正则,如果有大牛知道这里面我错在哪里了,真心感谢你告诉我一下,谢谢。


3,boost regex

 

点击(此处)折叠或打开

  1. /* write by xingming
  2.  * for:test boost regex
  3.  * time:2012年10月23日11:35:33
  4.  * */

  5. #include <iostream>
  6. #include <string>
  7. #include <sys/time.h>
  8. #include "boost/regex.hpp"

  9. using namespace std;
  10. using namespace boost;
  11. const int times = 10000000;

  12. int main()
  13. {
  14.     regex pattern("finance\\.sina\\.cn|stock1\\.sina\\.cn|3g\\.sina\\.com\\.cn.*(channel=finance|_finance$|ch=stock|/stock/)|dp\\.s
  15. ina\\.cn/.*ch=9&");
  16.     cout<<"input strings:"<<endl;
  17.     timeval start,end;
  18.     gettimeofday(&start,NULL);
  19.     string input[] = {"finance.sina.cn/google.com/baidu.com.google.sina.cn",
  20.                       "3g.com.sina.cn.google.com.baidu.com.sina.egooooooooo",
  21.                       ""};
  22.     for(int i = 0 ;i < times; ++ i)
  23.     {
  24.         for(int j = 0 ; j < 3;++j)
  25.         {
  26.             //if(input=="quit")
  27.             // break;
  28.             //cout<<"string:'"<<input<<'\''<<endl;
  29.             cmatch what;
  30.             if(regex_search(input[j].c_str(),what,pattern)) ;
  31.             // cout<<"OK!"<<endl;
  32.             else ;
  33.             // cout<<"error!"<<endl;
  34.         }
  35.     }
  36.     gettimeofday(&end,NULL);
  37.     uint time = (end.tv_sec-start.tv_sec)*1000000 + end.tv_usec - start.tv_usec;
  38.     cout<<time/1000000<<" s and "<<time%1000000<<" us."<<endl;
  39.     return 0 ;
  40. }

boost正则不用多说了,要是出去问,C++正则怎么用啊?那90%的人会推荐你用boost正则,他实现起来方便,正则库也很强大,资料可以找到很多,所以我也不在阐述了。


4,对比情况


总结:

C regex的速度让我吃惊啊,相比boost的速度,C regex的速度几乎要快上3倍,看来正则引擎的选取上应该有着落了!

上面的表格中我用到的正则和字符串是一样的(在代码中C regex的被我加长了),速度相差几乎有3倍,C的速度大约在30+w/s , 而boost的速度基本在15-w/s ,所以对比就出来了!

在这里Cregex的速度很让我吃惊了已经,但随后我的测试更让我吃惊。

我以前在.net正则方面接触的比较多,就写了一个.net版本的作为对比,
 

点击(此处)折叠或打开

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Text.RegularExpressions;

  6. namespace 平常测试
  7. {
  8.     class Program
  9.     {
  10.         static int times = 1000000;
  11.         static void Main(string[] args)
  12.         {
  13.             Regex reg = new Regex(@"(?>finance\.sina\.cn|stock1\.sina\.cn|3g\.sina\.com\.cn.*(?:channel=finance|_finance$|ch=stock|/stock/)|dp.sina.cn/.*ch=9&)",RegexOptions.Compiled);
  14.             string[] str = new string[]{@"finance.sina.cn/google.com/baidu.com.google.sina.cn",
  15.                     @"3g.com.sina.cn.google.com.baidu.com.sina.egooooooooo",
  16.                     @""};
  17.             int tt = 0;
  18.             DateTime start = DateTime.Now;
  19.             for (int i = 0; i < times; ++i)
  20.             {
  21.                 for (int j = 0; j < 3; ++j)
  22.                 {
  23.                     if (reg.IsMatch(str[j])) ;
  24.                         //Console.WriteLine("OK!");
  25.                     //else
  26.                         //Console.WriteLine("Error!");
  27.                 }
  28.             }
  29.             DateTime end = DateTime.Now;
  30.             Console.WriteLine((end - start).TotalMilliseconds);
  31.             Console.WriteLine(tt);
  32.             Console.ReadKey();
  33.         }
  34.     }
  35. }

结果发现,正则在不进行RegexOptions.Compiled 的时候,速度和C regex的基本一样,在编译只会,速度会比C regex快上一倍,这不由得让我对微软的那群人的敬畏之情油然而生啊。


但随后我去查看了一下该博客上面C regex的描述,发现我可以再申明正则的时候加入编译模式,随后我加入了上面代码里的 REG_NOSUB(在先前测试的时候是没有加入的),结果让我心理面很激动的速度出来了,C regex 匹配速度竟然达到了 300+w/s,也就是比原来的(不加入REG_NOSUB)的代码快了将近10倍。

之后我变换了匹配的字符串,将其长度生了一倍,达到每个100字符左右(代码里面所示),匹配速度就下来了,但是也能达到 100w/s左右,这肯定满足我们现在的需求了。

结果很显然,当然会选择C regex了。

 

阅读(656) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

COMPUTER-TECH2015-04-06 07:41:58

regcomp返回0时,才可进行regfree;否则,会出现释放空指针错误,例如,bionic/libc/upstream-netbsd/libc/regex/regfree.c:110: regfree: assertion "preg->re_magic == MAGIC1" failed

COMPUTER-TECH2015-02-05 10:17:10

很棒的文章,赞一下!!!