正则表达式教程之二

注释

小括号的另一种用途是通过语法(?#comment)来包含注释。例如:2[0-4]/d(?#200-249)|25[0-5](?#250-255)|[01]?/d/d?(?#0-199)

要包含注释的话,最好是启用忽略模式里的空白符选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。

例如,我们可以前面的一个表达式写成这样:

      (?<=    # 断言要匹配的文本的前缀

      <(/w+)> # 查找尖括号括起来的字母或数字(HTML/XML标签)

      )       # 前缀结束

      .*      # 匹配任意文本

      (?=     # 断言要匹配的文本的后缀

      <///1>  # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签

      )       # 后缀结束

   

贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。考虑这个表达式:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aabab(为什么第一个匹配是aab而不是ab?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权——The Match That Begins Earliest Wins)。

5.懒惰限定符

*?

重复任意次,但尽可能少重复

+?

重复1次或更多次,但尽可能少重复

??

重复0次或1次,但尽可能少重复

{n,m}?

重复nm次,但尽可能少重复

{n,}?

重复n次以上,但尽可能少重复

处理选项

上面介绍了几个选项如忽略大小写,处理多行等,这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项:

6.常用的处理选项

名称

说明

IgnoreCase(忽略大小写)

匹配时不区分大小写。

Multiline(多行模式)

更改^$的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配/n之前的位置以及字符串结束前的位置.)

Singleline(单行模式)

更改.的含义,使它与每一个字符匹配(包括换行符/n)。

IgnorePatternWhitespace(忽略空白)

忽略表达式中的非转义空白并启用由#标记的注释。

RightToLeft(从右向左查找)

匹配从右向左而不是从左向右进行。

ExplicitCapture(显式捕获)

仅捕获已被显式命名的组。

ECMAScript(JavaScript兼容模式)

使表达式的行为与它在JavaScript里的行为一致。

一个经常被问到的问题是:是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较相似(以至于让人感到疑惑)以外。

平衡组/递归匹配

注意:这里介绍的平衡组语法是由.Net Framework支持的;其它语言/库不一定支持这种功能,或者支持此功能但需要使用不同的语法。

有时我们需要匹配像( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构,这时简单地使用/(.+/)则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如( 5 / ( 3 + 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢?

为了避免(/(把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把xx <aa <bbb> <bbb> aa> yy这样的字符串里,最长的配对的尖括号内的内容捕获出来?

这里需要用到以下的语法构造:

  • (?'group') 把捕获的内容命名为group,并压入堆栈
  • (?'-group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
  • (?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
  • (?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败

如果你不是一个程序员(或者你是一个对堆栈的概念不熟的程序员),你就这样理解上面的三种语法吧:第一个就是在黑板上写一个 "group",第二个就是从黑板上擦掉一个"group",第三个就是看黑板上写的还有没有"group",如果有就继续匹配yes部分,否则就匹配 no部分。

我们需要做的是每碰到了左括号,就在黑板上写一个"group",每碰到一个右括号,就擦掉一个,到了最后就看看黑板上还有没有--如果有那就证明左括号比右括号多,那匹配就应该失败。

<                         #最外层的左括号

    [^<>]*                #最外层的左括号后面的不是括号的内容

    (

        (

            (?'Open'<)    #碰到了左括号,在黑板上写一个"Open"

            [^<>]*       #匹配左括号后面的不是括号的内容

        )+

        (

            (?'-Open'>)   #碰到了右括号,擦掉一个"Open"

            [^<>]*        #匹配右括号后面不是括号的内容

        )+

    )*

    (?(Open)(?!))         #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败

>                         #最外层的右括号

平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的<div>标签<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>.

还有些什么东西没提到

我已经描述了构造正则表达式的大量元素,还有一些我没有提到的东西。下面是未提到的元素的列表,包含语法和简单的说明。你可以在网上找到更详细的参考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到关于.net下正则表达式详细的文档。

7.尚未详细讨论的语法

/a

报警字符(打印它的效果是电脑嘀一声)

/b

通常是单词分界位置,但如果在字符类里使用代表退格

/t

制表符,Tab

/r

回车

/v

竖向制表符

/f

换页符

/n

换行符

/e

Escape

/0nn

ASCII代码中八进制代码为nn的字符

/xnn

ASCII代码中十六进制代码为nn的字符

/unnnn

Unicode代码中十六进制代码为nnnn的字符

/cN

ASCII控制字符。比如/cC代表Ctrl+C

/A

字符串开头(类似^,但不受处理多行选项的影响)

/Z

字符串结尾或行尾(不受处理多行选项的影响)

/z

字符串结尾(类似$,但不受处理多行选项的影响)

/G

当前搜索的开头

/p{name}

Unicode中命名为name的字符类,例如/p{IsGreek}

(?>exp)

贪婪子表达式

(?<x>-<y>exp)

平衡组

(?im-nsx:exp)

在子表达式exp中改变处理选项

(?im-nsx)

为表达式后面的部分改变处理选项

(?(exp)yes|no)

exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no

(?(exp)yes)

同上,只是使用空表达式作为no

(?(name)yes|no)

如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no

(?(name)yes)

同上,只是使用空表达式作为no

联系作者

好吧,我承认,我骗了你,读到这里你肯定花了不止30分钟.相信我,这是我的错,而不是因为你太笨.我之所以说"30分钟",是为了让你有信心,有耐心继续下去.既然你看到了这里,那证明我的阴谋成功了.上这种当的滋味还不错吧?

要投诉我,或者觉得我其实可以做得更好,或者有任何其它问题,欢迎来我的博客进行讨论.

最后,来点广告...

一些我认为你可能已经知道的术语的参考

字符

程序处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等等。

字符串

0个或更多个字符的序列。

文本

文字,字符串。

匹配

符合规则,检验是否符合规则,符合规则的部分。

断言

声明一个应该为真的事实。只有当断言为真时才会对正则表达式继续进行匹配。

网上的资源及本文参考文献

Mastering Regular Expressions (Second Edition)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值