天天看點

C++中三種正規表達式比較(C regex,C ++regex,boost regex)

工作需要用到C++中的正規表達式,是以就研究了以上三種正則。

1,C regex

C++中三種正規表達式比較(C regex,C ++regex,boost regex)
C++中三種正規表達式比較(C regex,C ++regex,boost regex)
/*  write by xingming
 *  time:2012年10月19日15:51:53
 *  for: test regex
 *  */

#include <regex.h>
#include <iostream>
#include <sys/types.h>
#include <stdio.h>
#include <cstring>
#include <sys/time.h>

using namespace std;
const int times = 1000000;

int main(int argc,char** argv)
{
    char pattern[512]="finance\.sina\.cn|stock1\.sina\.cn|3g\.sina\.com\.cn.*(channel=finance|_finance$|ch=stock|/stock/)|dp.sina.cn/.*ch=9&";
    const size_t nmatch = 10;
    regmatch_t pm[10];
    int z ;
    regex_t reg;
    char lbuf[256]="set",rbuf[256];
    char buf[3][256] = {"finance.sina.cn/google.com/baidu.com.google.sina.cndddddddddddddddddddddda.sdfasdfeoasdfnahsfonadsdf",
                    "3g.com.sina.cn.google.com.dddddddddddddddddddddddddddddddddddddddddddddddddddddbaidu.com.sina.egooooooooo",
                    "http://3g.sina.com.cn/google.baiduchannel=financegogo.sjdfaposif;lasdjf.asdofjas;dfjaiel.sdfaosidfj"};
    printf("input strings:\n");
    timeval end,start;
    gettimeofday(&start,NULL);
    regcomp(&reg,pattern,REG_EXTENDED|REG_NOSUB);
    for(int i = 0 ; i < times; ++i)
    {
        for(int j = 0 ; j < 3; ++j)
        {
            z = regexec(&reg,buf[j],nmatch,pm,REG_NOTBOL);
/*          if(z==REG_NOMATCH)
                printf("no match\n");
            else
                printf("ok\n");
                */
        }
    }
    gettimeofday(&end,NULL);
    uint time = (end.tv_sec-start.tv_sec)*1000000 + end.tv_usec - start.tv_usec;
    cout<<time/1000000<<" s and "<<time%1000000<<" us."<<endl;
    return 0 ;
}      
C++中三種正規表達式比較(C regex,C ++regex,boost regex)

使用正規表達式可簡單的分成幾步:

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

C++中三種正規表達式比較(C regex,C ++regex,boost regex)
C++中三種正規表達式比較(C regex,C ++regex,boost regex)
/*  write by xingming
 *  time:2012年10月19日15:51:53
 *  for: test regex
 *  */

#include <regex>
#include <iostream>
#include <stdio.h>
#include <string>

using namespace std;

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

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

        if(buf == "quit")
        {
            printf("quit just now!\n");
            break;
        }

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

        if(!valid)
            printf("no match!\n");
        else
            printf("ok\n");
    }

    return 0 ;
}      
C++中三種正規表達式比較(C regex,C ++regex,boost regex)

C++這個真心不想多說它,測試過程中發現 字元比對的時候 ‘a' 是可以比對的,a+也是可以的,[[:w:]]也可以比對任意字元,但[[:w:]]+就隻能比對一個字元,+号貌似不起作用了。是以後來就幹脆放棄了這偉大的C++正則,如果有大牛知道這裡面我錯在哪裡了,真心感謝你告訴我一下,謝謝。

3,boost regex

C++中三種正規表達式比較(C regex,C ++regex,boost regex)
C++中三種正規表達式比較(C regex,C ++regex,boost regex)
/* write by xingming
 * for:test boost regex
 * time:2012年10月23日11:35:33
 * */

#include <iostream>
#include <string>
#include <sys/time.h>
#include "boost/regex.hpp"

using namespace std;
using namespace boost;
const int times = 10000000;

int main()
{
    regex  pattern("finance\\.sina\\.cn|stock1\\.sina\\.cn|3g\\.sina\\.com\\.cn.*(channel=finance|_finance$|ch=stock|/stock/)|dp\\.s
ina\\.cn/.*ch=9&");
    cout<<"input strings:"<<endl;
    timeval start,end;
    gettimeofday(&start,NULL);
    string input[] = {"finance.sina.cn/google.com/baidu.com.google.sina.cn",
                      "3g.com.sina.cn.google.com.baidu.com.sina.egooooooooo",
                      "http://3g.sina.com.cn/google.baiduchannel=financegogo"};
    for(int i = 0 ;i < times; ++ i)
    {
        for(int j = 0 ; j < 3;++j)
        {
            //if(input=="quit")
            //  break;
            //cout<<"string:'"<<input<<'\''<<endl;
            cmatch what;
            if(regex_search(input[j].c_str(),what,pattern)) ;
            //  cout<<"OK!"<<endl;
            else ;
            //  cout<<"error!"<<endl;
        }
    }
    gettimeofday(&end,NULL);
    uint time = (end.tv_sec-start.tv_sec)*1000000 + end.tv_usec - start.tv_usec;
    cout<<time/1000000<<" s and "<<time%1000000<<" us."<<endl;
    return 0 ;
}      
C++中三種正規表達式比較(C regex,C ++regex,boost regex)

boost正則不用多說了,要是出去問,C++正則怎麼用啊?那90%的人會推薦你用boost正則,他實作起來友善,正則庫也很強大,資料可以找到很多,是以我也不在闡述了。

4,對比情況

機關(us) boost regex 機關(us) C regex
1 2 3 4 5 平均 1 2 3 4 5 平均
1w 218,699 218,700 1w 90,631 90,632
10w 2,186,109 2,194,524 2,188,762 2,186,343 2,192,902 2,191,350 10w 902,658 907,547 915,934 891,250 903,899 900,113
100w 25,606,021 28,633,984 28,956,997 26,912,245 26,909,788 27,669,546 100w 9,030,497 9,016,080 8,939,238 8,953,076 9,041,565 8,983,831
1000w 218,126,580 218,126,581 1000w 89,609,061 89,609,062
正則

finance\\.sina\\.cn|stock1\\.sina\\.cn|3g\\.sina\\.com\\.cn.*(channel=finance|_finance$|ch=stock|/stock/)|dp\\.s

ina\\.cn/.*ch=9&

正則 finance\.sina\.cn|stock1\.sina\.cn|3g\.sina\.com\.cn.*(channel=finance|_finance$|ch=stock|/stock/)|dp.sina.cn/.*ch=9&
字元串 {"finance.sina.cn/google.com/baidu.com.google.sina.cn" ,  字元串 {"finance.sina.cn/google.com/baidu.com.google.sina.cn" , 
"3g.com.sina.cn.google.com.baidu.com.sina.egooooooooo" ,  "3g.com.sina.cn.google.com.baidu.com.sina.egooooooooo" , 
"http://3g.sina.com.cn/google.baiduchannel=financegogo"}; ​​http://3g.sina.com.cn/google.baiduchannel=financegogo​​};

總結:

C regex的速度讓我吃驚啊,相比boost的速度,C regex的速度幾乎要快上3倍,看來正則引擎的選取上應該有着落了!

上面的表格中我用到的正則和字元串是一樣的(在代碼中C regex的被我加長了),速度相差幾乎有3倍,C的速度大約在30+w/s , 而boost的速度基本在15-w/s ,是以對比就出來了!

在這裡Cregex的速度很讓我吃驚了已經,但随後我的測試更讓我吃驚。

我以前在.net正則方面接觸的比較多,就寫了一個

.net版本的作為對比,

C++中三種正規表達式比較(C regex,C ++regex,boost regex)
C++中三種正規表達式比較(C regex,C ++regex,boost regex)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace 平常測試
{
    class Program
    {
        static int times = 1000000;
        static void Main(string[] args)
        {
            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);
            string[] str = new string[]{@"finance.sina.cn/google.com/baidu.com.google.sina.cn",
                    @"3g.com.sina.cn.google.com.baidu.com.sina.egooooooooo",
                    @"http://3g.sina.com.cn/google.baiduchannel=financegogo"};
            int tt = 0;
            DateTime start = DateTime.Now;
            for (int i = 0; i < times; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    if (reg.IsMatch(str[j])) ;
                        //Console.WriteLine("OK!");
                    //else
                        //Console.WriteLine("Error!");
                }
            }
            DateTime end = DateTime.Now;
            Console.WriteLine((end - start).TotalMilliseconds);
            Console.WriteLine(tt);
            Console.ReadKey();
        }
    }
}      
C++中三種正規表達式比較(C regex,C ++regex,boost regex)

結果發現,正則在不進行RegexOptions.Compiled 的時候,速度和C regex的基本一樣,在編譯隻會,速度會比C regex快上一倍,這不由得讓我對微軟的那群人的敬畏之情油然而生啊。

但随後我去檢視了一下該部落格上面C regex的描述,發現我可以再申明正則的時候加入編譯模式,随後我加入了上面代碼裡的 REG_NOSUB(在先前測試的時候是沒有加入的),結果讓我心理面很激動的速度出來了,C regex 比對速度竟然達到了 300+w/s,也就是比原來的(不加入REG_NOSUB)的代碼快了将近10倍。