威尼斯www.9778.com-威尼斯正版官方网站

C++ 中三种正则表明式相比较

日期:2020-01-15编辑作者:编程人生

3、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 ;
}

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

1.4.3     Character classes

character class 是除了字面匹配最基本的正则表达式。它是很小的字符序列匹配更大的字符序列。例如,[A-Z]可以表示字母表,d表示任意数字。character class应用于BRE和ERE。

当使用范围通配符时,例如[a-z]。计算机本地设置决定了字符编码的顺序。计算机可能按a-z的顺序来存储,或者abc…zABC…Z,或者aAbBcC…zZ的顺序。所以POSIX定义了character class,正则表达式的处理器可以正确解析该character class。

POSIX

ASCII

描述

[:alnum:]

[A-Za-z0-9]

数字和字母字符

[:alpha:]

[A-Za-z]

字母字符

[:blank:]

[ t]

空格和TAB

[:cntrl:]

[x00-x1Fx7F]

控制符

[:digit:]

[0-9]

数字

[:graph:]

[x21-x7E]

可视字符

[:lower:]

[a-z]

小写字母字符

[:print:]

[x20-x7E]

可视字符和空格

[:punct:]

[][!"#$%&'()*+,./:;<=>?@^_`{|}~-]

标点符号

[:space:]

[ trnvf]

空白字符

[:upper:]

[A-Z]

大写字母字符

[:xdigit:]

[A-Fa-f0-9]

十六进制字符

POSIX定义的character class只能在中括号内使用。例如,[[:upper:]ab]匹配大写字母字符和”a”,”b”。

[:word:]是附加的非POSIX的character class,[:word:]表示[:alnum:]和下划线。这表明在很多编程语言中,这些通配符可能是标识符。

2、C++ 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%sn********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("okn");
    }

    return 0 ;
}

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

1.3.2     regexec

1、C 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 matchn");
            else
                printf("okn");
                */
        }
    }
    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 ;
}

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

  • 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 函数会自动截断超出的字符串,但他仍然会返回完整的字符串的长度。所以我们可以用如下的方法先得到错误字符串的长度。

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

函数原型

  void regfree(regex_t *preg);

总结:

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

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

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

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

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

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

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

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

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

功能

  将regcomp和regexec返回的errorcode转换成错误信息。

4、对比情况

图片 1

  REG_EPAREN

    EPAREN=error parenthesis

    圆括号不匹配

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

1.3.1     regcomp

函数原型

  size_t regerror(int errcode, const regex_t *preg, char *errbuf,

                       size_t errbuf_size);

   REG_NEWLINE

  识别换行符。

      ‘^’匹配行的开头, 不管regexec中是否设置eflags为REG_NOTBOL

   ‘$’匹配行的末尾, 不管regexec中是否设置eflags为REG_NOTEOL

   例如:pattern=”^a$” 被检测字符串为”na”,那么设置REG_NEWLINE才能匹配成功。

cflags

  决定编译的类型。

1.4.2     Extended Regular Expressions

在ERE中,反斜杠’’用来对通配符进行转义,所以BRE中的’(’和’)’在ERE中改为’(’和’)’,’{’和’}’改为’{’和’}’。 ERE移除了’n’通配符,并添加了如下通配符。

通配符

描述

?

匹配前一个元素0次或1次。例如,ab?c匹配”ac”,”abc”。

+

匹配前一个元素1次或多次。例如,ab+c匹配”abc”,”abbc”等,但是不能匹配”ac”。

|

匹配前一个表达式或后一个表达式。例如,abc|def匹配”abc”,”def”。

   REG_NOTBOL

  NOTBOL = not-begin-of-line

  不匹配行的开头,除非在regcomp编译时cflag设置REG_NEWLINE。

  该标志位可能在如下情况使用,传递string的不同部分给regexec,并且string的开头不能被解释成行的开头。

   REG_BADBR

    BR=back reference

    非法使用返回引用操作符

参数含义

    REG_EXTENDED

  扩展的正则表达式,如果不设置则为基本的正则表达式。

   REG_BADRPT

    RPT=repetition

    非法使用重复的操作符,例如在第一个字符使用 ’*’

eflags

1       POSIX正则表达式

1.3.4     regefree

pmatch

  匹配到的数组。

  regmatch_t 的定义如下

  typedef struct {

  regoff_t  rm_so;

  regoff_t  rm_eo;

  } regmatch_t;

  rm_so

如果-1==rm_so,表示没有匹配到。

如果-1!=rm_so,表示string中下一个最大子字符串的偏移量(举例string开头的偏移量)。

  rm_eo

子字符串的长度。

函数原型

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

   REG_EBRACE

    EBRACE=error brace

    大括号不匹配

   REG_EEND

    EEND=error end

    无具体错误。该错误码在POSIX.2中没有定义

 

  REG_NOTEOL

  NOTEOL = not-end-of-line

  不匹配行的结束,除非在regcomp编译时cflag设置REG_NEWLINE。

regex

  描述正则表达式的字符串。

regcomp方法返回的错误码

返回值

  返回errbuf存储错误信息所需要的大小。

  如果errbuf和errbuf_size都是非0,那么errbuf中有errbuf_size-1大小错误信息字符串,最后是字符串结束标记(‘’)。

功能

  编译正则表达式,以便regexec方法使用。

1.1     头文件

#include <regex.h>

参数含义

  REG_ESPACE

    ESPACE=error space

    编译正则表达式已经超出内存空间

   REG_BADPAT

    PAT=pattern

    非法使用正则表达式操作符,例如group和list

nmatch

  匹配到的字符串的个数。

errbuf_size

  errbuf的大小。

1.4.1     基本通配符

通配符

描述

.

匹配任何一个单字符(许多应用不包括换行符,但是假设包括换行符也是安全的)。在大中小括号中,该通配符只匹配字符’.’,例如,a.c匹配”abc”,但是[a.c]只匹配”a”或”.”或”c”。要匹配’.’不能使用’.’,因为’.’的作用与’.’一样,应该使用’[.]’来匹配”a.c”中的点。

[]

只匹配中括号内的一个字符。例如[abc]匹配”a”或”b”或”c”。[a-z]匹配小写的”a”到”z”。这些格式可以混合使用:[abcx-z]匹配”a”,”b”,”c”,”x”,”y”,”z”与[a-cx-z]的效果相同。

‘-’如果出现在[]的开头或结尾,表示匹配字符’-’,例如[^-abc],[-abc] ,[abc-]。注意不能使用’’。

‘]’可以出现在中括号中的第一个位置,例如[]abc]或[^]abc]

[^ ]

匹配单个字符,该字符不能包含在中括号中。例如,[^abc]匹配任何除’a’,’b’,’c’外的字符。[^a-z]匹配任何除’a’-‘z’的字符。同理,字符与范围标识可以混合使用,例如,[^a-cx-z]。

^

匹配字符串的开头。在基于行的工具中,匹配每一行的开头。

$

匹配字符串的结尾或者换行符的前一个位置。在基于行的工具中,匹配每一行的结尾。

()

定义一个子表达式。圆括号在整体匹配完后进行匹配。子表达式也叫做块或组。

BRE模式需要写成()

n

匹配第n(1<=n<=9)个子表达式。POSIX.2对该通配符的定义很模糊,有的工具允许引用大于9的子表达式。

*

匹配前一个元素0次或多次。例如,ab*c匹配”ac”,”abc”,”abbbbbc”等。[xyz]*匹配””,”x”,”y”,”z”,”zx”,”zyx”,”xyzzy”等。(ab)*匹配””,”ab”,”abab”等。

{m,n}

匹配前一个元素至少m次,至多n次。例如,a{3,5}匹配”aaa”,”aaaa”,”aaaaa”。

BRE模式需要写成{m,n}

举例

.at

匹配任何以”at”结尾长度为3的字符串,例如” at”,”aat”,”cat”等

[hc]at

匹配”hat”和”cat”

[^b]at

除了”bat”,匹配任何以”at”结尾长度为3的字符串。例如,”aat”,”cat”等

[^hc]at

除了”hat”和”cat”,匹配任何以”at”结尾长度为3的字符串。例如,”aat”,”tat”等

^[hc]at

匹配任何以”hat”或”cat”开头的字符串或行

[hc]at$

匹配任何以”hat”或”cat”结尾的字符串或行

[.]

匹配任何三个字符,第一个和第三个字符必须分别为”[”,”]”,因为”[”和”[”是经过转义,例如”[a]”,”[b]”

s.*

匹配任何以”s”开头的字符串,例如”swa”,”seed”

string

  待匹配的字符串。

函数原型

  int regexec(const regex_t *preg, const char *string, size_t nmatch,

                   regmatch_t pmatch[], int eflags);

    REG_ICASE

  不区分大小写。

 

目录

1 POSIX正则表达式

1.1 头文件

1.2 注意事项

1.3 基本方法

1.4 POSIX正则表达式基本规范

1.5 源码示例

返回值

  void

举例

[hc]+at

匹配”hat”,”cat”,”hhat”,”ccat”等,但是不匹配”at”

[hc]?at

匹配”hat”,”cat”,”at”

[hc]*at

匹配”at”,”hat”,”cat”,”hcat”等

cat|dog

匹配”cat”,”dog”

preg

  preg是一个指向编译后的正则表达式p意思是pointer,reg意思是regex_t类型。

  regex_t是一个结构体数据类型,用来存放编译后的正则表达式,它的成员re_nsub用来存储正则表达式中的子正则表达式的个数,子正则表达式就是用圆括号包起来的部分表达式。

参数含义

1.3     基本方法

errbuf

  存储错误信息的buffer。

   REG_ESUBREG

    ESUBREG=error reference to a subexpression

    非法使用子表达式的引用

preg

  经过regcomp编译的正则表达式。

  REG_ESIZE

    ESIZE=error size

    编译正则表达式需要的内存大于64kb,在POSIX.2中没有定义

功能

  释放由regcomp编译preg的内存。

preg

  经过regcomp编译的正则表达式。

   REG_EBRACK

    EBRACK=error bracket

    中括号不匹配

参数含义

  REG_ECTYPE

    ECTYPE=error character type

    错误的字符类型

1.2     注意事项

    不过在C++的字符串中,''表示转义后面的字符,'\'才表示一个'',而在正则中,''也表示转义,所以一个'正常'的正则在修改为C++正则时,所有的''都要加倍。

    POSIX**正则表达式有自己的一套规范,与常用的正则表达式不完全相同**。

1.4     POSIX正则表达式规范

参考:

  POSIX正则表达式分为Basic Regular Expressions 和 Extended Regular Expressions。

  ERE增加支持?,+和|,去除了通配符()和{}。而且POSIX正则表达式的标准语法经常坚持使用附加的语法来支持特殊应用。虽然POSIX.2没有实现一些具体的细节,BRE和ERE提供被很多工具使用的标准。

  BRE要求通配符()和{}写成()和{},ERE中无需这样。

错误码

   REG_NOSUB

  不用存储匹配后的结果。

  如果设置该标志位,那么在regexec将忽略nmatch和pmatch两个参数。

1.3.3     regerror

errorcode

  错误码,由regcomp或regexec获得。

   REG_ECOLLATE

    ECOLLATE=error collate

    非法参数

返回值

       成功返回0

     失败返回错误码

  REG_ERANGE

    ERANGE=error range

    非法使用范围操作符,例如结束的标识出现在开始标识之前

1.5     源码示例

我的github:

libutil库中包含有regex的示例。欢迎批评指正,一起修改。

 

/******************************************************************************  libutil  Author: zhaokai  Email: loverszhao@gmail.com    Reference: POSIX    Description:    Version: 1.0    ******************************************************************************/    #include "util/regex_util.h"    #include <algorithm>  #include <climits>  #include <iostream>  #include <regex.h>    namespace util  {    bool  RegexMatch(const std::string &_pattern,             const std::string &_input,             std::vector<std::string> *_output,             std::string *_err_msg)  {    _output->clear();    *_err_msg = "";    regex_t reg;      int comp_result = regcomp(&reg, _pattern.c_str(), REG_EXTENDED | REG_NEWLINE);    if (0 == comp_result)    {      // Add 1 in case of "" == _input      size_t nmatch = 1 + std::min(_input.length(), UINT_MAX - 1);      regmatch_t pmatch[nmatch];      int exec_result = regexec(&reg, _input.c_str(), nmatch, pmatch, 0);        if (0 == exec_result)      {        for (size_t i = 0; i < nmatch; ++i)        {          if (-1 == pmatch[i].rm_so)            break;            _output->push_back(_input.substr(pmatch[i].rm_so, pmatch[i].rm_eo));        }      }    }    else    {      const size_t errbuf_size = 1000;      char errbuf[errbuf_size + 1];      regerror(comp_result, &reg, errbuf, errbuf_size);      *_err_msg = errbuf;            regfree(&reg);      return false;    }      regfree(&reg);    return true;  }    bool  FullMatch(const std::string &_pattern,            const std::string &_input)  {    std::vector<std::string> output;    std::string err_msg = "";    bool result = RegexMatch(_pattern, _input, &output, &err_msg);      if (!result)    {      std::cout << err_msg << std::endl;      return false;    }    else    {      // full-match in case of @_input == output[0]      if (0 < output.size() && _input == output[0])        return true;    }    return false;  }    }; // namespace util

 

单元测试文件,包含了Mac,IP,Port,文件夹路径的正则表达式测试

 

/******************************************************************************  libutil  Author: zhaokai  Email: loverszhao@gmail.com    Reference: chromium    Description:    Version: 1.0    ******************************************************************************/    #include "util/regex_util.h"    #include "util/basictypes.h"    #include "third_party/gtest/include/gtest/gtest.h"    namespace util  {  // ------------------------------------------------------------  // --------------------- Update Begin -------------------------  // ------------------------------------------------------------    TEST(RegexUtilTest, RegexMatch)  {    struct    {      const std::string pattern;      const std::string input;      const std::vector<std::string> expect_output;      bool result;    } cases [] = {      { "c", "c", {"c"}, true},      { "c", "", {}, true},      { "(", "", {}, false},      { "0*", "", {""}, true},      { "0*", "0", {"0"}, true},      { "0*", "0000", {"0000"}, true},    };      for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)    {      std::string err_msg = "";      std::vector<std::string> output;      EXPECT_EQ(cases[i].result, RegexMatch(cases[i].pattern, cases[i].input, &output, &err_msg))          << "cases[" << i << "]";      EXPECT_EQ(cases[i].expect_output, output)          << "cases[" << i << "]";    }  }    TEST(RegexUtilTest, FullMatch)  {    struct    {      const std::string pattern;      const std::string input;      bool result;    } cases [] = {      { "c", "c", true},      { "c", "", false},      { "(", "", false},      { "^[0-9]*$", "12345", true},      { "^[0-9]*$", "00000", true},      { "^[0-9]*$", "1", true},      { "\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", "loverszhao@gmail.com", true},      { "[0-9]{5}", "00000", true},      { "([0-9]){5}", "00000", true},      { "(([0-9]){5}){2}", "0000000000", true},      { "(([0-9]){5}){2}", "0000011111", true},      { "(([0-9]){5}){2}", "0123456789", true},      { "[0-9]", "0", true},      { "0*", "00000", true},      { "0*", "", true},      { "0?", "", true},      { "0?", "0", true},      { "0?", "00", false},      { "[a-z][0-9]{2}{3}", "x000000", true},      { "^a$", "a", true},      { "^a$", "na", false},      { ".", "a", true},      { ".", "abc", false},      { ".", ".", true},      { "[.]", "a", false},      { "[:digit:]", "1", false},      { "[[:digit:]]", "1", true},      { "[[:digit:]]{1,2}", "1", true},      { "[[:digit:]]{1,2}", "99", true},      { "^[[:digit:]]{1,2}", "1", true},      { "^[[:digit:]]{1,2}", "99", true},      //"^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5]).";      { "^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]])", "99", true},      { "^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]])", "199", true},      { "^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])", "99", true},      { "^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])", "199", true},      { "^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])", "239", true},      { "^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])", "250", true},      { "^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5]).", "250.", true},      { "^([\/]?[[:alnum:]_]+)*$", "file_name", true},            };      for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)    {      EXPECT_EQ(cases[i].result, FullMatch(cases[i].pattern, cases[i].input))          << "cases[" << i << "] pattern=" << cases[i].pattern          << " input=" << cases[i].input << std::endl;    }  }      namespace  {    // Return true if @_mac is valid, such as "11:11:11:11:11:11"  // or "11 11 11 11 11 11" or "111111111111"  // flase otherwise  bool  ValidateMac(const std::string &_mac)  {    const std::string pattern = "^[0-9a-fA-F]{2}([ -:][0-9a-fA-F]{2}){5}";    return FullMatch(pattern, _mac);  }        // Return true if @_ip is valid, such as "192.168.4.1"  // flase otherwise  bool  ValidateIP(const std::string &_ip)  {    const std::string pattern =        "^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])[.]"        "([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])[.]"        "([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])[.]"        "([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])$";      return FullMatch(pattern, _ip);  }    // Return true if @_port is valid which should between "0~65535"  // and it can be "0" or "65535"  // false otherwise  bool  ValidatePort(const std::string &_port)  {    const std::string pattern = "^([1-9]|[1-9][[:digit:]]{1,3}|[1-6][0-5][0-5][0-3][0-5])$";    return FullMatch(pattern, _port);  }    // Return true if @_path is valid, such as "/1/2/3" or "1/2/3/"  // false otherwise  bool  ValidatePath(const std::string &_path)  {    //const std::string pattern = "^[a-zA-Z]:(((//(?! )[^///:*?"<>|]+)+//?)|(//))[:space:]*$";    //const std::string pattern = "(^[.]|^/|^[a-zA-Z])?:?/[.]+(/$)? ";    //const std::string pattern = "(/([0-9a-zA-Z]+))+";    const std::string pattern = "^([\/]?[[:alnum:]_]+)*$";    return FullMatch(pattern, _path);  }    TEST(RegexUtilTest, ValidateMac)  {    struct    {      const std::string input;      bool result;    } cases [] = {      { ":11:22:33:44:55:66", false},      { "11:22:33:44:55:66", true},      { "11-22-33-44-55-66", true},      { "11 22 33 44 55 66", true},      { "112233445566", false},      { "c", false},      { "c", false},      { "(", false},    };      for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)    {      EXPECT_EQ(cases[i].result, ValidateMac(cases[i].input))          << "cases[" << i << "] input=" << cases[i].input << std::endl;    }  }    TEST(RegexUtilTest, ValidateIP)  {    struct    {      const std::string input;      bool result;    } cases [] = {      // Normal IP      { "192.168.4.1", true},      { "10.0.0.1", true},      { "192.168.4.244", true},      // Unnormal IP      { "292.168.4.244", false},      { "192.268.-1.244", false},      { "192.168.4.264", false},      { "....", false},      { "192.168.1.", false},      { "192 168 1 1", false},    };      for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i)    {      EXPECT_EQ(cases[i].result, ValidateIP(cases[i].input))          << "cases[" << i << "] input=" << cases[i].input << std::endl;    }  }    TEST(RegexUtilTest, ValidatePort)  {    struct    {      const std::string input;      bool result;    } cases [] = {      // Normal Port      { "1", true},      { "99", true},      { "199", true},      { "200", true},      { "999", true},      { "1999", true},      { "30000", true},      { "30001", true},      { "60000", true},      { "65535", true},        // Unnormal Port      { "0", false},      { "-1", false},      { "00", false},      { "010", false},      { "65536", false},      { "65537", false},      { "111111", false},    };      for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) 

功能

  根据编译好的正则表达式,对字符串进行匹配。

返回值

  成功返回0

  失败返回REG_NOTMATCH

   REG_EESCAPE

    EESCAPE=error escape

    多余的

preg

  经过regcomp编译的正则表达式。

本文由威尼斯www.9778.com发布于编程人生,转载请注明出处:C++ 中三种正则表明式相比较

关键词:

Google C++ 编程风格指南:作用域

通常每一个  .cc  文件都有一个对应的  .h  文件. 也有一些常见例外,如单元测试代码和只包含  main()  函数的  .c...

详细>>

威尼斯正版官方网站new与malloc的10点区别

堆内存 vs. 内存池 Allocator类在“释放列表”为空时,能够从堆内存或者内存池中申请新内存。如果使用内存池,你必...

详细>>

如何做好数据分析师的职业规划?

一、为什么要学习数据分析? 近几年来,无论是科研院所,商业巨头还是初创企业,各行各业都在大力开发或者引进...

详细>>