Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1736486
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: C/C++

2012-03-27 12:42:03

Brain Kernighan

正则表达式是描述文本模式的记法(notation),它由Stephen Kleen在上世纪50年代中期发明,最初出现在Ken Thompson的QED文本编辑器中,之后移植到Unix的编辑器ed中,然后又被移植到Unix工具grep中。Jeffrey Friedl的《Mastering Regular Expression》对其进行了详细研究。

Rob Pike在1998年与Brain Kernighan编写《The Practice of Programming》时,给出了用于教学的示例代码:一个最小的正则表达示软件包,它可以处理以下的模型:

字符

含义

c

匹配任意的字母c

.(句点)

匹配任意的单个字符

^

匹配输入字符串的开头

$

匹配输入字符串的结尾

*

匹配前一个字符的零个或多个出现

下面是Rob的(C语言)代码:


  1. int match(char* regexp, char* text)
  2. {
  3.     if (*regexp == '^')
  4.         return matchhere(regexp+1, text);
  5.     do {
  6.         if (matchhere(regexp, text))
  7.             return 1;
  8.     } while (*text++ != '\0');
  9.     return 0;
  10. }

  11. int matchhere(char* regexp, char* text)
  12. {
  13.     if (regexp[0] == '\0')
  14.         return 1;
  15.     if (regexp[1] == '*')
  16.         return matchstar(regexp[0], regexp+2, text);
  17.     if (regexp[0] == '$' && regexp[1] == '\0')
  18.         return *text == '\0';
  19.     if (*text != '\0' && (regexp[0] == '.' || regexp[0] == *text))
  20.         return matchhere(regexp+1, text+1);
  21.     return 0;
  22. }

  23. int matchstar(int c, char* regexp, char* text)
  24. {
  25.     do {
  26.         if (matchhere(regexp, text))
  27.             return 1;
  28.     } while (*text != '\0' && (*text++ == c || c == '.'));
  29.     return 0;
  30. }

函数match首先判断输入的正则表达式是否以“^”开头,如果是则尝试匹配整个字符串,否刚迭代地尝试匹配其所有子字符串。do...while形式的 迭代保证了text为空时仍可以进行匹配。matchhere里,只要它的首字符匹配,则继续递归调用matchhere来匹配下一字符,当regexp 为空时便表示完全匹配。对于特殊符号"*",单独使用函数matchstar来匹配。matchstar可以识别“最短匹配”。

为了实现最长匹配,可以修改matchstar:


  1. int matchstar(int c, char* regexp, char* text)
  2. {
  3.     char* t;
  4.     for (t = text; *t != '\0' && (*t == c || c == '.'); t++)
  5.         ;
  6.     do {
  7.         if (matchhere(regexp, t))
  8.             return 1;
  9.     } while (t-- > text);
  10.     return 0;
  11. }

它首先将尽可能多的匹配字符c,而后每次匹配失败再回退进行下一次尝试。

 

Brian对Rob的代码的紧凑性和优雅性高度赞扬,认为这段代码短小而且强大,并分析了它为什么能如此短小:
首先,它很好地选择了一个功能集合,挑选了正则表达式中最核心而又最具代表性的东西。比如,它挑选了“*”,但没有实现“+”和“?”这些类似的字符。


其次,它成功地使用了递归。从正则表达式的开头和text的开头剥离匹配字符,对剩余的字符进行递归。这样比显示循环产生更短,更整洁以及更优雅的代码。


最后,它使用了(C语言)基本的语法来实现良好的效果。利用指针提取单个字符和传递下一个字符。
 

:1942年1月生,加拿大计算机科学家,现任普林斯顿计算机科学的教授。曾在贝尔实验室与Unix创始人Ken Thompson和Dennis Ritchie同共开发Unix。代表作有《C programming language》、《AWK》、《AMPL programming languages》等。

阅读(2329) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~