Regular Expression Notes

开始真正了解RE是从这篇开始的。RE实在是博大精深,且把之前学到的东西再整理回忆下了。

正则表达式就是记录文本规则的代码

前面那句话说的好,RE是描述的一种字符排列的规则,这就有两个要素:

1、表达形式

表达形式包含了主体和组合方式

a) 主体:各种字符,不管一个正则表达式的字符代表了一个还是一类字符,总之,这些主体是可以看到的

b) 组合方式:也就是位置,同样的字符,位置不同,排列不同,表示的字符串也不同

所以说,表达形式这块的内容,可以直接地从RE匹配的结果中看出来。

 

.

匹配除换行符"\n"之外的任意字符

\b

代表单词的开头或结尾,即单词的分界处[ \b匹配这样的位置:它的前一个字符和后一个字符不全是\w ]
RE中的单词:不少于一个的连续的\w

\d

一位数字(0,1,2……9)

\s

任意空白符:空格,制表符,换行符,中文全角空格

\w

字母或数字或下划线或汉字等

^

字符串的开始

$

字符串的结束

+

前面内容匹配1次或多次

*

表示数量:前边的内容可以连续重复使用任意次是整个表达式匹配,0次或多次

?

重复0次或1次

{n}

重复n次

{n,}

重复n次或多次

{n,m}

重复n次到m次

\

匹配某些特殊符号时,取消符号的特殊含义: \--\\*--\*.--\.(--\()--\)

[aeiou]

匹配一个字符,候选值为aeiou

[0-9]

匹配一个数字,候选值为0,1,2,3,4,5,6,7,8,9
反义:大写表示与小写相反的含义

\W

任意不是字母、数字、下划线、汉字的字符

\S

任意非空字符

\D

任意非数字字符

\B

不是单词开头或结束的位置

[^x]

除x意外的任意字符

[^aeiou]

除aeiou以外的任意字符

2、表达方式

在表达形式之上,如何合理、精确、简短地描述规则,就是表达方式的范畴,比如:分支、分组、后向引用、零宽断言、贪心与懒惰、递归匹配等。

可能有人会说,上一行提到的这些东西,也有是直接反映在结果中的。我相说的是,表达方式各种方法的使用,使表达形式更简洁、精确,其实有些没有也行,比如:后向引用,很显然的一个例子。

分枝条件

用“|”将不同的规则分隔开
eg.
> 国内固定电话:0\d{2}-\d{8} | 0\d{3}-\d{7}  以“-”分割,3位区号和四位区号
> 国内固定电话,3位或4位区号,区号可以用“-”与号码隔开,也可以用()隔开,也可以用空格,也可以什么都没有:
\(?0\d{2}\)?[- ]?\d{8} | \(?0\d{3}\)?[- ]?\d{7} 
bug: 对01234567890没法分出3位还是4位区号;对(012-34567890无匹配成功
((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)

支持手机号码,3-4位区号,7-8位直播号码,1-4位分机号
> 美国邮政编码:\d{5}-\d{4} | \d{5}  9位,前5位后有“-”分割,或是只有5位
(注意各个条件的顺序 如果是\d{5} | \d{5}-\d{4},则值匹配5位的邮编或位的前5位,在有分枝时,只要满足一个就算匹配完成,后面会提到的Lazy原则)

分组

重复一组字符,用()来指定子表达式,即为分组
eg.
> IP地址:
((2[0-4]\d | 25[0-5] | [01]?\d\d?)\.){3}(2[0-4]\d | 25[0-5] | [01]?\d\d?)

后向引用

指定子表达式(分组)后,用编号引用前面的分组,自添加的分组编号默认从1开始,\1 表示分组1匹配的文本。分组0匹配整个正则表达式。
eg.
重复的单词,如"go go"
(\b(\w+)\b)\s+\1\b
可以自己给分组指定组名:(?<GroupName>expr)或(?'GroupName'expr)
[ 组号匹配过程要扫描两边:1、扫描未命名的分组;2、扫描命名分组 ]
eg.
> IP地址:
((?<IP>2[0-4]\d | 25[0-5] | [01]?\d\d?)\.){3}\k<IP>

零宽断言

“零宽”表示这个语法不在匹配串中占用任何字符
“断言”表示条件不满足即可退出
确保匹配串附近出现了某些字符
(?=exp) 零宽度正预测先行断言:断言自身出现的位置的后面能匹配表达式exp
匹配串后面是exp
eg.
> 一篇文章中结尾为ing的词中除ing之外的部分:
\b\w+(?=ing\b?) 
Rolling in the deep  它匹配  Roll
(?<=exp) 零宽度正回顾后发断言:断言自身出现的位置的前面能匹配表达式exp
匹配串前面是exp
eg.
> 匹配以re开头的词中除re之外的部分:
(?<=\bre)\w+\b
reading a book  它匹配ading
> 以空白符间隔的数字(不包含这些空白符)
(?<=\s)\d+(?=\s)

负向零宽断言

确保匹配串附近没有出现某些字符
(?!exp) 零宽度负预测先行断言:断言此位置的后面不能匹配表达式exp
匹配串后面不能是exp
eg.
> 后面不是字母u的q的单词:
\b\w*q(?!u)\w*\b
(?<!exp) 零宽度负回顾后发断言:断言此位置后前面不能匹配表达式exp
匹配串前面不能是exp
eg.
前面不是小写字母的七位数字:
(?!<[a-z])\d{7}
不含属性的简单HTML标签的内容:
(?<=<\w+>).*(?=<\/\1>)

注释

(?#comment)
eg.
IP地址:
((?<IP>2[0-4]\d(?#200-249) | 25[0-5](?#250-255) | [01]?\d\d?(?#0-199))\.){3}\k<IP>

贪心

当RE中包含能接受重复的限定符是,通常是在能匹配的前提下,匹配尽可能多的字符。
eg.
a.*b 匹配最长的以a开始,以b结束的字符串
对aabab,会匹配整个字符串

懒惰

匹配尽可能少的字符
在前面的限定符后面加?即可转化为懒惰模式
eg.
a.*?b 对aabab得到的匹配是aab和ab两个
*? 重复0次或多次,但尽可能少重复
+? 重复1次或多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n次到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

最先匹配

最先开始的匹配具有最高的优先级 优先级高于贪心或懒惰

 

上面的思路或许不那么严谨,只是讲讲我自己按照怎么样的逻辑去理解这套东西的。

posted @ 2012-08-31 16:57  郝玉琨  阅读(283)  评论(2编辑  收藏  举报