Chinaunix首页 | 论坛 | 博客
  • 博客访问: 94009
  • 博文数量: 32
  • 博客积分: 960
  • 博客等级: 准尉
  • 技术积分: 335
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-22 23:09
文章分类

全部博文(32)

文章存档

2011年(31)

2010年(1)

我的朋友

分类:

2011-02-20 01:25:27

正则表达式,一般简称regex、regexp、re,广泛应用于grep、vim、sed等。 具体实现很多,比较常见的有regex和pcre。

regex,是posix接口,多数C标准库自带,Linux下通过/usr/include/regex.h或者man regex查看。

接口只有四个:regcomp、regexec、regerror、regfree
      #include
  #include
  #include
  #define SUBSLEN 10              /* 匹配子串的数量 */
  #define EBUFLEN 128          /* 错误消息buffer长度 */
  #define BUFLEN 1024          /* 匹配到的字符串buffer长度 */
  int main()
  {
  size_t       len;
  regex_t       re;      /* 存储编译好的正则表达式,正则表达式在使用之前要经过编译 */
  regmatch_t    subs [SUBSLEN]; /* 存储匹配到的字符串位置 */
  char          matched [BUFLEN];     /* 存储匹配到的字符串 */
  char          errbuf [EBUFLEN]; /* 存储错误消息 */
  int          err, i;
  char          src    [] = "111 Hello World 222"; /* 源字符串 */
  char          pattern [] = "(.*)"; /* pattern字符串 */


  printf("String : %s\n", src);
  printf("Pattern: \"%s\"\n", pattern);


  /* 编译正则表达式 */
  err = regcomp(&re, pattern, REG_EXTENDED);
  if (err)

      {
  len = regerror(err, &re, errbuf, sizeof(errbuf));
  printf("error: regcomp: %s\n", errbuf);
  return 1;
  }
  printf("Total has subexpression: %d\n", re.re_nsub);


  /* 执行模式匹配 */
  err = regexec(&re, src, (size_t) SUBSLEN, subs, 0);
  if (err == REG_NOMATCH)

      { /* 没有匹配成功 */
  printf("Sorry, no match ...\n");
  regfree(&re);
  return 0;
  }

      else if (err)

      {   /* 其它错误 */
  len = regerror(err, &re, errbuf, sizeof(errbuf));
  printf("error: regexec: %s\n", errbuf);
  return 1;
  }
  /* 如果不是REG_NOMATCH并且没有其它错误,则模式匹配上 */
  printf("\nOK, has matched ...\n\n");
  for (i = 0; i <= re.re_nsub; i++)

      {
  len = subs[i].rm_eo - subs[i].rm_so;
  if (i == 0)

      {
  printf ("begin: %d, len = %d   ", subs[i].rm_so, len); /* 注释1 */
  }

      else

      {
  printf("subexpression %d begin: %d, len = %d   ", i, subs[i].rm_so, len);
  }
  memcpy (matched, src + subs[i].rm_so, len);
  matched[len] = '\0';
  printf("match: %s\n", matched);
  }
  regfree(&re); /* 用完了别忘了释放 */
  return (0);
  }


  执行结果是
  CODE:String : 111 Hello World 222
  Pattern: "(.*)"
  Total has subexpression: 1
  OK, has matched ...
  begin: %, len = 4   match: Hello World
  subexpression 1 begin: 11, len = 11   match: Hello World


  从示例程序可以看出,使用之前先用regcomp()编译一下,然后调用regexec()进行实际匹配。如果只是看有没有匹配成功,掌握这2个函数的用法即可。

      有时候我们想要取得匹配后的子表达式,比如示例中想获得title是什么,需要用小括号 "( )"把子表达式括起来"(.*)",表达式引擎会将小括号 "( )" 包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候,小括号包含的表达式所匹配到的字符串可以单独获取,示例程序就是我用来获取http网页的主题(title)的方式。
  regmatch_t subs[SUBSLEN]是用来存放匹配位置的,subs[0]里存放这个匹配的字符串位置,subs[1]里存放第一个子表达式的匹配位置,也就是例子中的title,通过结构里的rm_so和rm_eo可以取到,这一点很多人不太注意,应该强调一下。
  注释1:开始调试代码的时候是在FreeBSD 6.2上进行的,print出来的len总是0,但print出来的字符串又没错,很是迷惑,把它放到Linux上则完全正常,后来仔细检查才发现rm_so在Linux上是32位,在FreeBSD上是64位,用%d的话实际取的是rm_so的高32位,而不是实际的len,把print rm_so的地方改为%llu就可以了。
  regex虽然简单易用,但对正则表达式的支持不够强大,中文处理也有问题,于是引出了下面要说的PCRE。

pcre(Perl Compatible Regular Exprssions),有完善的使用说明和示例代码。

接口很多,常用的有:pcre_compile()、pcre_study()、pcre_exec()、pcre_free()。

将上面的regex代码修改如下:

  #include
  #include
  #include
  #define OVECCOUNT 30 /* should be a multiple of 3 */
  #define EBUFLEN 128
  #define BUFLEN 1024
  int main()
  {
  pcre          *re;
  const char    *error;
  int          erroffset;
  int          ovector[OVECCOUNT];
  int          rc, i;
  char          src [] = "111 Hello World 222";
  char          pattern [] = "(.*)";


  printf("String : %s\n", src);
  printf("Pattern: \"%s\"\n", pattern);


  re = pcre_compile(pattern, 0, &error, &erroffset, NULL);
  if (re == NULL)

      {
  printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
  return 1;
  }


  rc = pcre_exec(re, NULL, src, strlen(src), 0, 0, ovector, OVECCOUNT);
  if (rc < 0)

      {
  if (rc == PCRE_ERROR_NOMATCH)

            printf("Sorry, no match ...\n");
  else

            printf("Matching error %d\n", rc);


  free(re);
  return 1;
  }
  printf("\nOK, has matched ...\n\n");


  for (i = 0; i < rc; i++)

      {
  char *substring_start = src + ovector[2*i];
  int substring_length = ovector[2*i+1] - ovector[2*i];
  printf("%2d: %.*s\n", i, substring_length, substring_start);
  }


  free(re);
  return 0;
  }


  执行结果是:
  CODE:String : 111 Hello World 222
  Pattern: "(.*)"
  OK, has matched ...
  0: Hello World
  1: Hello World
  比较这2个例子可以看出,在regex用的是regcomp()、regexec(),pcre则使用pcre_compile()、pcre_exec(),用法几乎完全一致。

      pcre_study,可以加速匹配;如果编译之后多次使用,可以使用该功能。
  pcre_compile()有很多选项,详细说明参见。

      如果是多行文本,可以设置PCRE_DOTALL的选项pcre_complie(re, PCRE_DOTALL,....),表示'.'也匹配回车换行"\r\n"。


参考了很多网络资料,部分链接如下,在此一并致谢!
声明:本人博客仅供个人学习用途,无意侵权;如果任何人有任何异议,请及时发消息通知本人修改。谢谢!


阅读(2037) | 评论(0) | 转发(0) |
0

上一篇:Java基础

下一篇:重新编译Kernel

给主人留下些什么吧!~~