一、GNU Regex Library 1. 什么是GNU正则表达式库(GNU Regex Library) ? GNU正则表达式库是glibc(GNU C Library)的一部分,它提供与POSIX标准兼容的正则表达式匹配的接口。 这里是其主页:http://www.gnu.org/s/libc/manual/html_node/Regular-Expressions.html 下载该库点这里:gnuregex0_13
2. GNU Regex Library所提供的接口 (1)regcomp:
1 2 3 4 5 6 | int regcomp(regex_t *preg, const char *pattern, int cflags) 功能:将要进行匹配的正则表达式pattern进行编译,做匹配前的准备工作 参数: preg, 输出参数,用来保存编译后的正则表达式结果 pattern, 输入参数,传入要进行编译的正则表达式的字符串 cflags, 输入参数,用来指定正则表达式匹配过程中的一些选项 返回值:编译成功返回0,失败返回非0的错误码 | (2)regexec:
1 2 3 4 5 6 7 8 9 | int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) 功能:用来检测字符串string是否匹配正则表达式preg 参数: preg, 输入参数,在(1)regcomp中编译好的正则表达式规则 string, 输入参数,用来被匹配的字符串 nmatch, 输入参数,用来指定pmatch参数所对应的数组的长度 pmatch, 输出参数,用来输出在string中匹配preg的具体位置 eflag, 输入参数,用来指定正则表达式匹配过程中的一些选项 返回值: 如果string匹配preg所指定的规则,则返回0, 否则返回非0 | (3)regerror:
1 2 3 4 5 6 7 | size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) 功能:用来把在regcompt和regexec中产生的错误码转化成字符串形式的错误信息 参数: errcode, 输入参数,在regcomp或regexec调用中返回的错误码 preg, 输入参数,与错误码所对应的编译过的正则表达式结构 errbuf, 输出参数,用来返回错误信息的buffer,如果buffer不够所需大小,错误信息将被截断 errbuf_size, 输入参数,返回错误信息的buffer的大小 返回值: 如果errbuf_size为0,那么regerror返回错误信息所需要的buffer的大小 | (4)regfree:
1 2 3 4 | void regfree (regex_t *preg) 功能: 用来释放由regcomp编译时生成的preg结构所占用的内存 参数: preg, 输入参数,由regcomp编译时生成的正则表达的结构指针 返回值: 无 | 3. 使用GNU Regex Library的一些注意事项 (1)regcomp与regfree必须配对使用,要不然会造成内存泄漏(类比malloc/free, new/delete) (2)regex_t结构:把字符串形式的正则表达式编译成regex_t这样的一个结构,方便后续的匹配工作 (3)regmatch_t结构:用来表示正则表达式中字符串中匹配的位置的结构,用起始位置的偏移量来表示的 (4)flags:用来配置匹配过程中的一些选项, 指定如何匹配,具体参见:http://www.opengroup.org/onlinepubs/007908799/xsh/regcomp.html (5)使用该库需要包含的头文件:sys/types.h和regex .h
4. GNU Regex Library使用举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <sys /types.h> #include <regex .h> #include <stdio .h> int main(int argc, char ** argv) { if (argc != 3) { printf("Usage: %s RegexString Text/n", argv[0]); return 1; } const char * pRegexStr = argv[1]; const char * pText = argv[2]; regex_t oRegex; int nErrCode = 0; char szErrMsg[1024] = {0}; size_t unErrMsgLen = 0; if ((nErrCode = regcomp(&oRegex, pRegexStr, 0)) == 0) { if ((nErrCode = regexec(&oRegex, pText, 0, NULL, 0)) == 0) { printf("%s matches %s/n", pText, pRegexStr); regfree(&oRegex); return 0; } } unErrMsgLen = regerror(nErrCode, &oRegex, szErrMsg, sizeof(szErrMsg)); unErrMsgLen = unErrMsgLen < sizeof(szErrMsg) ? unErrMsgLen : sizeof(szErrMsg) - 1; szErrMsg[unErrMsgLen] = '/0'; printf("ErrMsg: %s/n", szErrMsg); regfree(&oRegex); return 1; } | 程序测试:
1 2 3 4 5 | wuzesheng@wuzesheng-ubuntu:~/Program$ gcc TestRegex.c -o Regex wuzesheng@wuzesheng-ubuntu:~/Program$ ./Regex "http:www/..*/.com" "https://www.taobao.com" ErrMsg: No match wuzesheng@wuzesheng-ubuntu:~/Program$ ./Regex "http:www/..*/.com" "http://www.taobao.com" http://www.taobao.com matches http:www/..*/.com | 二、PCRE、PCRE++ 1. 什么是PCRE? 什么是PCRE++? PCRE,全称是Perl Compatible Regular Expressions。从名字我们可以看出PCRE库是与Perl中正则表达式相兼容的一个正则表达式库。PCRE是免费开源的库,它是由C语言实现 的,这里是它的官方主页:http://www.pcre.org/,感兴趣的 朋友可以在这里了解更多的内容。 要得到PCRE库,可以从这里下载:http://sourceforge.net/projects/pcre/files/ PCRE++是一个对PCRE库的C++封装,它提供了更加方便、易用的C++接口。这里是它的官方主页:http://www.daemon.de/PCRE,感兴趣的朋友可以在 这里了解更多的内容。 要得到PCRE++库,可以从这里下载:http://www.daemon.de/PcreDownload
2. PCRE接口介绍 (1). pcre_compile
1 2 3 4 5 6 7 8 9 10 | pcre *pcre_compile(const char *pattern, int options, const char **errptr, int *erroffset, const unsigned char *tableptr); 功能:编译指定的正则表达式 参数:pattern, 输入参数,将要被编译的字符串形式的正则表达式 options, 输入参数,用来指定编译时的一些选项 errptr, 输出参数,用来输出错误信息 erroffset, 输出参数,pattern中出错位置的偏移量 tableptr, 输入参数,用来指定字符表,一般情况用NULL, 使用缺省的字符表 返回值:被编译好的正则表达式的pcre内部表示结构 | (2). pcre_exec
1 2 3 4 5 6 7 8 9 10 11 12 13 | int pcre_exec(const pcre *code, const pcre_extra *extra, const char *subject, int length, int startoffset, int options, int *ovector, int ovecsize); 功能:用来检查某个字符串是否与指定的正则表达式匹配 参数: code, 输入参数,用pcre_compile编译好的正则表达结构的指针 extra, 输入参数,用来向pcre_exec传一些额外的数据信息的结构的指针 subject, 输入参数,要被用来匹配的字符串 length, 输入参数, 要被用来匹配的字符串的指针 startoffset, 输入参数,用来指定subject从什么位置开始被匹配的偏移量 options, 输入参数, 用来指定匹配过程中的一些选项 ovector, 输出参数,用来返回匹配位置偏移量的数组 ovecsize, 输入参数, 用来返回匹配位置偏移量的数组的最大大小 返回值:匹配成功返回非负数,匹配返回负数 | 3. PCRE++接口介绍 PCRE++把PCRE库封装成了两个类,一个是RE_Options, 用来指定匹配选项,一个是RE,用来提供匹配相关的接口。RE_options类在这里我就不介绍了,我主要介绍一下RE类: (1)RE的构造函数传入正则表达式,并在构造函数中调用Init函数,将该正则表达进行编译 (2)RE的pattern()成员用来得到初始传入的正则表达式字符串 (3)RE的error()成员用来得到匹配过程中的出错信息 (4)RE的FullMatch()成员用来判断某字符串整体是否匹配指定正则表达式 (5)RE的PartialMatch()成员用来判断某字符串的部分是否匹配指定正则表达式 4. PCRE/PCRE++使用注意事项 (1)使用pcre请包含pcre.h头文件 (2)使用pcre_compile, pcre_exec后,记得调用pcre_free释放内存,以免造成内存泄露 (3)使用pcre编译的时候需要依赖libpcre.a (4)使用pcre++请包含pcrecpp.h头文件 (5)使用pcre++,RE类的析构函数会自动释放相关内存,因此不用担心内存泄露 (6)使用pcre++编译的时候需要依赖libpcrecpp.a (7)使用pcrecpp要使用pcrecpp命名空间
5. PCRE使用举例 下面是例程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <pcre .h> #include <stdio .h> #include <string .h> int main(int argc, char ** argv) { if (argc != 3) { printf("Usage: %s pattern text/n", argv[0]); return 1; } const char * pPattern = argv[1]; const char * pText = argv[2]; const char * pErrMsg = NULL; pcre * pPcre = NULL; int nOffset = -1; if (NULL == (pPcre = pcre_compile(pPattern, 0, &pErrMsg, &nOffset, NULL))) { printf("ErrMsg=%s, Offset=%d/n", pErrMsg, nOffset); return 1; } else { if (pcre_exec(pPcre, NULL, pText, strlen(pText), 0, 0, NULL, 0) < 0) { printf("%s doesn't match %s/n", pText, pPattern); } else { printf("%s matches %s/n", pText, pPattern); } } } | 下面是运行结果:
1 2 3 4 5 6 | wuzesheng@wuzesheng-ubuntu:~/Program$ !g++ g++ -lpcre TestPcre.cpp -o pcre wuzesheng@wuzesheng-ubuntu:~/Program$ ./pcre "http:.*/.qq/.com" "http://www.qq.com" http://www.qq.com matches http:.*/.qq/.com wuzesheng@wuzesheng-ubuntu:~/Program$ ./pcre "http:.*/.qq/.com" "http://www.qqq.com" http://www.qqq.com doesn't match http:.*/.qq/.com | 6. PCRE++使用举例 下面是例程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <iostream> #include <pcrecpp .h> int main(int argc, char ** argv) { if (argc != 3) { std::cerr < < "Usage: " << argv[0] << " pattern text/n"; return 1; } pcrecpp::RE oPattern(argv[1]); if (oPattern.FullMatch(argv[2])) { std::cout << argv[2] << " fully matches " << argv[1] << "/n"; } else if (oPattern.PartialMatch(argv[2])) { std::cout << argv[2] << " partially matches " << argv[1] << "/n"; } else { std::cout << argv[2] << " dose not match " << argv[1] << "/n"; } } | 下面是运行结果:
1 2 3 4 5 6 7 8 9 | wuzesheng@wuzesheng-ubuntu:~/Program$ g++ TestPcreCpp.cpp -lpcrecpp -o pcrecpp wuzesheng@wuzesheng-ubuntu:~/Program$ ./pcrecpp Usage: ./pcrecpp pattern text wuzesheng@wuzesheng-ubuntu:~/Program$ ./pcrecpp "http:.*/.qq/.com" "http://www.qq.com" http://www.qq.com fully matches http:.*/.qq/.com wuzesheng@wuzesheng-ubuntu:~/Program$ ./pcrecpp "http:.*/.qq/.com" "http://www.qq.comiii" http://www.qq.comiii partially matches http:.*/.qq/.com wuzesheng@wuzesheng-ubuntu:~/Program$ ./pcrecpp "http:.*/.qq/.com" "http://www.qqq.comiii" http://www.qqq.comiii dose not match http:.*/.qq/.com | 以上即是关于PCRE和PCRE++库介绍的全部内容,由于内容比较多,我只介绍了一些关键的接口及其用法,如果读者朋友想更加深入的了解其它的接 口,可以参考我上面提到的官方网站,另外linux下的manual也是很好的参考资料。在shell下执行man pcre和man pcrecpp便可得到很详细的资料。 2、 //code by yangjian:useage: ./cmd regex < string.txt #include<stdio.h> #include<regex.h> #define nmatch 1 //char* string="<div>;test</div>/n"; char string[4096]; char ret[1024]; main(int agrc,char *argv[]) { // fgets(lbuf, sizeof(lbuf), stdin); regex_t preg; //char * regex="abc+"; char * regex=argv[1]; char * cur; regmatch_t pmatch [nmatch]; int i; fread(string,sizeof(string),1,stdin); bzero(&preg,sizeof(regex_t)); if(regcomp(&preg,regex,REG_EXTENDED)!=0) { printf("compile regex error!!"); } cur=string; //printf("str: %s",cur); i=0; while(regexec(&preg,cur,nmatch,pmatch,0)==0) { //pmatch[0].rm_so==-1; //memset( pmatch, 0x00, sizeof(pmatch)); if(pmatch[0].rm_so==-1) { break; } memset( ret, 0x00, sizeof(ret)); memcpy( ret,cur+pmatch[0].rm_so,pmatch[0].rm_eo-pmatch[0].rm_so); printf("%d: ",i++); printf("%s/n/n",ret); cur+=pmatch[0].rm_eo; //printf("str: %s/n",cur); } regfree(&preg); } 这是一个比较通用的程序。它会读入整个文本文件作为一个字符串来进行匹配。并非按行读取。注意这行: while(regexec(&preg,cur,nmatch,pmatch,0)==0) 实验证明,实际上它每次执行regexec它找个第一个匹配结果就返回了。不要妄想它一下子把所有的匹配结果都找到把地址放到pmatch数组里。书上的写发很容易让人造成这种误解。因为它每次只匹配一个结果就返回,所以要循环匹配。 好了,先回去睡觉了。有空再写。时间不早了。 ./a.out "<td[a-z0-9=%<>/ ]+.{2,20}[ a-z/<>]+td>" < string.txt |