正则表达式详解

来源:互联网 发布:abode acrobat mac 编辑:程序博客网 时间:2024/05/16 07:58

Jerffrey E.F.Friedl著的这本书,闻名已久。九月份从当当网邮购了一本,却一直没有时间坚持读,主要原因当然还是英文差,没有养成阅读英文的习惯和能力。

后悔呀,当初为什么不多花点时间在英语上面。

开篇说的那个可怕的、查找重复单词的需求非常生动,如果是我遇到这样的需求,肯定同样会很苦恼。

  • 检查N个文件,找到重复的单词(比如“this this”),然后报出它们在哪个文件的哪一行,还要用标准ANSI的转义序列来高度显示它们;
  • 不仅如此,还要正确处理这种情况:某行的最后一个单词,与紧跟着的下一(非空)行的第一个单词相同,也就是说要能够跨行工作。
  • 在 查找过程中,还要忽略大小写的区别,并且能把单词之间的任意数量空格都等同于单个空格对待,最重要的是,两个重复单词中的某一个或两个被HTML标记包围 着,那还是算重复单词!比如“...it is <B>very</B> very important...”

这样的需求听上去很讨厌,但有了正则表达式,一切就变得容易了。

下表是基本的元字符:

元字符
名称
匹配行为
备注
^ 脱字符 匹配行的起始位置   $ 美圆符 匹配行的结束位置   /< 反斜杠及小于符 匹配单词的起始边界 不是所有版本的的egrep都支持这个特性 /> 反斜杠及大于符 匹配单词的结束边界 . 点 匹配任意单个字符
[...] 字符集 匹配所有方括号中列出的字符
[^...] 字符非集 匹配所有不在方括号中列出的字符   | 或符号 匹配或符号分开的的表达式   (...) 圆括号 用于指定“或”符号的范围  

注:

  • 如果一个元字符出现在字符集中(被方括号括起来的字符列表),则它不再是元字符,比方,点字符在方括号以外时,它是一个元字符,代表任意字符,如果它出现在方括号里,则代表点字符本身。
  • 在字符集和字符非集中中,如果减号字符出现在第一个字符位置,则它代表减号本身,否则它表示一个范围,比如[-a-z0-9],第一个减号代表减号本身,第二个减号表示范围,与字符a和z一起表示从a至z的26个英文小写字母,第三个减号与第二个减号的意义一样。
  • 字符非集的概念需要仔细,比如,[^X]意味着“只要不是字符X就匹配”,而是“匹配一个不是X的任意字符”,前者的意义可以匹配一个空行,但[^X]并不匹配空行。
  • 某些版本的egrep支持-i参数,以执行忽略大小写的匹配操作。


圆括号

圆括号有两种用法

  • 将“或”操作(“|“符号)的两个值括起来,比如(ABC|abc)
  • 将多个字符括起来做为一个整体,使之可以用?、+、* 或{m,n}来限定该整体的匹配次数

反向引用

当被圆括号括住的整体被匹配时,该匹配能够被正则表达式工具记住,并由/1、/2、/3……来引用第一个、第二个、第三个……匹配。例如,本书开篇所讲的那个找出重复单词的例子,可以由如下正则表达式来匹配:

/b([A-Za-z]+)/s+/1/b

其中/b匹配单词边界,/s匹配空格、制表符、换行符等“空白分界”,/1是反向引用,引用的是圆括号括起来的整体匹配。(要点,要使用反向引用,必须要用圆括号将匹配括起来,否则正则表达式无法记住那个匹配)


这本书的第2章,开始简单地介绍了一下Perl,首先是把开篇那个“查找重复单词”问题的解决方案列了出来,一段简短的Perl代码:

00001: $/ = "./n";
00002: while (<>) {
00003:     next if !s//b([a-z]+)((?:/s|<[^>]+>)+)(/1/b)//e[7m$1/e[m$2/e[7m$3/e[m/ig;
00004:     s/^(?:[^/e]*/n)+//mg;
00005:     s/^/$ARGV: /mg;
00006:     print;
00007: }

Perl的一些基础语法是:

  • 变量由$开头,如$celsius(见下面朋友的指正)
  • 变量的类型可以是数值型或字符型
  • 注释由#开头(可以是单行注释,也可以是行尾注释)
  • 字串常量用双引号括起来,与其它语言(如C)不同的是,用双引号内出现的变量名(由$开头),会被变量的值替换
  • 用print输出
  • Perl命令行的可选参数-w,让Perl使用更高级别的语法检查,并打印警告信息(比如变量未被始化就使用、声明了变量却未使用等)
  • if ($foo =~ m/^/d+$/) 这样的语法是在测试“$foo这个变量的值匹配^/d+$这个正则表达式”的布尔结果。=~这个操作符既不是等于(==),也不是赋值(=),而是“是否匹配”
  • 正则表达式用两个斜杠/字符括起来,前面的m表示匹配操作(可选),如果把m换成s,则表示“替换”

本书第2章简单地介绍了一下Perl,完全任自己的猜想臆断,总结了上面几条,下面是好友Buchi Automata的指正:

严 格说,是scalar variable(标量变量?)由$开头。如果是矢量变量,则由@开头。比如@arr = [1, 2, 3, 4]。如果是hash,则用%开头。比如%h = {1=>'a', 2=>'b'}。RE前面的m有它的作用。有了m,我们可以用任何配对的符号表示RE。比如/pattern/ 和 m{pattern} 和m&pattern&都一个意思。



一、Non-Capturing

这个Non-Capturing的确不知道该如何翻译(非捕获?),但意思是明白了。用圆括号括起来的部分可以被捕获到$1、$2……中,但如果起始圆括号后面紧跟一个问号和冒号,就表示本组不需要被捕获到$1、$2……中。

例如,下列正则表达式中

^([-+]?/d+(/./d*)?)([CF])$
  • 第1个被捕获的组:从第一个左圆括号,到与该左圆括号配对的右括号,被存储到$1中(整数+小数点+小数部分)
  • 第2个被捕获的组:从第二个左圆括号,到与该左圆括号配对的右括号,被存储到$2中(小数点+小数部分)
  • 第3个被捕获的组:从第三个左圆括号,到与该左圆括号配对的右括号,被存储到$3中(C或F)

如果是下面的正则表达式:

^([-+]?/d+(?:/./d*)?)([CF])$

注意红色的部分,有了这个就表示本组不要捕获,这样,$2中存储的就是([CF])这一组,没有$3了。

二、字符转义

  • /bTAB字符(ASCII码9)
  • /n换行符(ASCII码10)
  • /r回车符(ASCII码13)
  • /s所有能代表“空白”的字符(包括空格、制表、换行等)
  • /S所有不是/s的字符
  • /w大小写字母、数字和下划线,与[a-zA-Z0-9_]等价
  • /W所有不是/w的字符,与[^a-zA-Z0-9_]等价
  • /d数字,与[0-9]等价
  • /D所有非数字字符,与[^0-9]等价

三、文本替换

先前知道了m的作用(匹配),把m换成s就成了“替换”,另外,好友告诉我有了m,就可以用任何一对符号来括住正则表达式,不必老是用/,说不定s也一样。

$name =~ s//bSaddam/b/Bush/;

这句表示:把$name里面存储的内容,凡是匹配到单词边界的Saddam,通通替换为Bush。

四、Perl的一些语法

while ($var = <>) {
}

这个“$var=<>”看起来有点古怪,其实就是“var = getline()”,也就是说,从输入流中取下一行的内容,并赋值变量中,如果输入流已结束,则变量值未定义,同时整个赋值表达式返回布尔假。

关键字last,与C里面的continue类似。

函数defined($var)测试一个变量里是否含有值,是则返回true,否则返回false。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1521776

 
原创粉丝点击