当前位置: 首页 >> 程序设计 >> 正则表达式在C++中的实现-POSIX库
 

正则表达式在C++中的实现-POSIX库

作者:      来源:zz     发表时间:2007-03-29     浏览次数:      字号:    

GNU/Linux有两套库可用于正则表达式编程:POSIX库和PCRE库。前者不需要单独安装,一般需求还是能满足的,速度稍慢些。后者是久负盛名的Perl正则表达式库,功能强大,匹配速度快,不过可能需要单独安装。

本文介绍如何使用POSIX库。

#i nclude <stdio.h>
#i nclude <sys/types.h>
#i nclude <regex.h>

char *get_regerror (int errcode, regex_t *compiled)
{
 size_t length = regerror (errcode, compiled, NULL, 0);
 char *buffer = malloc(length);
 if (!buffer) return NULL;
 (void) regerror (errcode, compiled, buffer, length);
 return buffer;
}

int regtest(const char*pattern, const char* string)
{
 regex_t reg;
 regmatch_t *subexprs = NULL;
 int ret;
 int i;

 if (0 != (ret=regcomp(?, pattern, REG_EXTENDED))) {
  char *buffer = get_regerror(ret, ?);
  if (buffer) {
   fprintf(stderr, "regcomp:[%d]%s\n", ret, buffer);
   free(buffer);
  }

  return -1;
 }

 subexprs = malloc((reg.re_nsub+1)*sizeof(regmatch_t));
 if (!subexprs) {
  fprintf(stderr, "error malloc subexprs\n");
  regfree(?);
  return -1;
 }

 if (0 != (ret=regexec(?, string, reg.re_nsub+1, subexprs, 0))) {
  char *buffer = get_regerror(ret, ?);
  if (buffer) {
   fprintf(stderr, "regexec:[%d]%s\n", ret, buffer);
   free(buffer);
  }
  
  regfree(?);
  return -1;
 }

 for (i = 0; i <= reg.re_nsub; i++)  {
  printf("[%d]:", i);
  
  if (subexprs[i].rm_so == subexprs[i].rm_eo) {
   printf("[EMPTY SUBEXPR]\n");
  }
  else if (subexprs[i].rm_so == -1 ||
   subexprs[i].rm_eo == -1) {
   printf("[NO SUBEXPR]\n");
  }
  else  {
   fwrite(string+subexprs[i].rm_so, 1,
    subexprs[i].rm_eo-subexprs[i].rm_so, stdout);
   printf("\n");
  }
 }

 regfree(?);
 if (subexprs) free(subexprs);
 return 0;
}

int main(int argc, char *argv[])
{
 if (argc != 3) {
  fprintf(stderr, "Usage: regtest pattern string\n");
  return -1;
 }

 fprintf(stderr, "pattern:%s\n", argv[1]);
 fprintf(stderr, "string:%s\n", argv[2]);

 return regtest(argv[1], argv[2]);
}

在字符串匹配之前,我们必须先编译匹配模式,这是通过regcomp实现的。这个函数的原型如下:

int regcomp (regex_t *compiled, const char *pattern, int cflags)

参数compiled只有一个成员是我们需要关注的,那就是re_nsub,代表编译后的子表达式数目,由于我们还需要保存整个匹配到的模式,所以最终匹配的条目数是re_nsub加1。cflags用来修饰匹配模式,可取值如下:

REG_EXTENDED 启用POSIX正则库扩展,关于该扩展的详细信息可参考POSIX规范
REG_ICASE 忽略大小写
REG_NOSUB 不要存储子表达式
REG_NEWLINE 把换行符作为多行的分隔符,这样'$'可匹配每一行的行尾,'^'匹配每一行的行首,'.'不匹配换行符,[^...]不匹配新行

编译完模式后我们从内存中分配子表达式存储空间,然后调用regexec对串进行匹配,该函数原型如下:

int regexec (regex_t *compiled, char *string, size_t nmatch, regmatch_t matchptr [], int eflags)

nmatch指明matchptr数组的数目,该数目是compiled->re_nsub+1,也可以让nmatch为0,matchptr为NULL,表示不要保存子表达式。eflags通常为0。

匹配结束后,匹配到的子表达式在串中的偏移保存在regmatch_t结构中,该结构有两个成员:

rm_so 子表达式的起始偏移
rm_eo 子表达式的结束偏移

这是一个开区间,实际的子表达式在[rm_so,rm_eo)里。

如果没有匹配的子表达式,比如"f(o*)"匹配"fum",实际匹配到的只有"f",这时rm_so和rm_eo相等,都为1。如果整个模式在没有子表示式的情况下也能匹配,这时rm_so和rm_eo为-1,比如"ba(na)*"匹配"ba"。

 void regfree(regex_t *preg);



函数regfree()不会返回任何结果,它仅接收一个指向regex_t数据类型的指针,这是之前调用regcomp()函数所得到的编译结果。



如 果在程序中针对同一个regex_t结构调用了多次regcomp()函数,POSIX标准并没有规定是否每次都必须调用regfree()函数进行释 放,但建议每次调用regcomp()函数对正则表达式进行编译后都调用一次regfree()函数,以尽早释放占用的存储空间。



报告错误信息



如果调用函数regcomp()或regexec()得到的是一个非0的返回值,则表明在对正则表达式的处理过程中出现了某种错误,此时可以通过调用函数regerror()得到详细的错误信息。

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

Param

参数errcode 是来自函数regcomp()或regexec()的错误代码,

参数preg 是由函数regcomp()得到的编译结果,

其目的是把格式化消息所必须的上下文提供给regerror()函数。

参数errbuf_size指明的最大字节数,

责任编辑 webmaster

 
 
 
 
 
评论更多>>
 
 
 
发表
 
姓名: QQ:
性别: MSN:
E-mail: 主页:
评分: 1 2 3 4 5
评论内容:
验证码:
  
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  •