Further Study of Rugular Expresions
更新时间:2008年09月24日 22:53:38 作者:
regular expressions(正则表达式,以下用re称呼)对小弟来说一直都是神密的地带,看到一些网络上的大大,简单用re就决解了 某些文字的问题
17. (\(\d{3}\)\d{3})\s?\d{3}[- ]\d{4} (十个数字的电话号码)
群组(grouping)
括号可以用来介定一个次描述,经由次描述的介定,可以针对次描述做重复或及他的处理。
18. (\d{1,3}\.){3}\d{1,3} (寻找网络地址的简单re)
此re的意思第一个部分(\d{1,3}\.){3},所指的是,数字最小一位最多三位,并且后面接有”.”符号,此类型的共有三个,之后再接一到三位的数字,也就是如192.72.28.1这样的数字。
但这样会有个缺点,因为网络地址数字最多只到255,但上述的re只要是一到三位的数字都是符合的,所以这需要让比较的数字小于256才行,但只单独使用re并无法做这样的比较。在19中使用择一来将地址的限制在所需要的范围内,也就是0到255。
19. ((2[0-4]\d25[0-5][01]?\d\d?)\.){3}(2[0-4]\d25[0-5][01]?\d\d?) (寻找网络地址)
有没有发觉re越来越像外星人说的话了?就以简单的寻找网络地址,直接看re都满难理解的哩。
expresso analyzer view
expresso提供了一个功能,它可以将所下的re变成树状的说明,一组组的分开说明,提供了一个好的除错环境。其它的功能,如部分符合 (partial match只查找反白re的部分)及除外符合(exclude match只不查找反白re的部分)就留给各位大大试试啰。
当次描述用括号群组起来时,符合次描述的文字可用在之后的程序处理或re本身。在预设的情型下,所符合的群组是由数字命名,由1开始,由顺序是由左至右,这自动群组命名,可在expresso中的skeleton view或result view中看到。
backreference是用来查找群组中抓取的符合文字所相同的文字。举例来说”\1”所指符合群组1所抓取的文字。
20. \b(\w+)\b\s*\1\b (寻找重复字,此处说的重复是指同样的字,中间有空白隔开如dog dog这样的字)
(\w+)会抓取至少一个字符的字母或数字的字,并将它命名为群组1,之后是查找任意空格符,再接和群组1相同的文字。
如果不喜欢群组自动命名的1,也可以自行命名,以上述例子为例,(\w+)改写为(?<word>\w+),这就是将所抓取的群组命名为word,backreference就要改写成为\k<word>
21. \b(?<word>\w+)\b\s*\k<word>\b (使用自行命名群组抓取重复字)
使用括号还有许多特别的语法元素,比较通用的列表如下:
抓取(captures)
(exp) 符合exp并抓取它进自动命名的群组
(?<name>exp) 符合exp并抓取它进命名的群组name
(?:exp) 符合exp,不抓取它
lookarounds
(?=exp) 符合字尾为exp的文字
(?<=exp) 符合前缀为exp的文字
(?!exp) 符合后面没接exp字尾的文字
(?<!exp) 符合前面没接exp前缀的文字
批注comment
(?#comment) 批注
positive lookaround
接下来要谈的是lookahead及lookbehind assertions。它们所查找的是目前符合之前或之后的文字,并不包含目前符合本身。 这些就如同”^”及”\b”特殊字符,本身并不会对应任何文字(用来界定位置),也因此称做是zero-width assertions,看些例子也许 会清楚些。
(?=exp)是一个”zero-width positive lookahead assertion”。它指的就是符合字尾为exp的文字,但不包含exp本身。
22. \b\w+(?=ing\b) (字尾为ing的字,比如说filling所符合的就是fill)
(?<=exp)是一个”zero-width positive lookbehind assertion”。它指的就是符合前缀为exp的文字,但不包含exp本身。
23. (?<=\bre)\w+\b (前缀为re的字,比如说repeated所符合的就是peated)
24. (?<=\d)\d{3}\b (在字尾的三位数字,且之前接一位数字)
25. (?<=\s)\w+(?=\s) (由空格符分隔开的字母数字字符串)
negative lookaround
之前有提到,如何查找一个非特定或非在特定群组的字符。但如果只是要验证某字符不存在而不要对应这些字符进来呢?举个例子来说,假设要查找一个字,它的字母里有q但接下来的字母不是u,可以用下列的re来做。
26. \b\w*q[^u]\w*\b (一个字,其字母里有q但接下来的字母不是u)
这样的re会有一个问题,因为[^u]要对应一个字符,所以若q是字的最后一个字母,[^u]这样的下法就会将空格符对应下去,结果就有可能会符合二个字,比如说”iraq haha”这样的文字。使用negative lookaround就能解决这样的问题。
27. \b\w*q(?!u)\w*\b (一个字,其字母里有q但接下来的字母不是u)
这是”zero-width negative lookahead assertion”。
28. \d{3}(?!\d) (三个位的数字,其后不接一个位数字)
同样的,可以使用(?<!exp),”zero-width negative lookbehind assertion”,来符合前面没接exp前缀的文字符串。
29. (?<![a-z ])\w{7} (七个字母数字的字符串,其前面没接字母或空格)
30. (?<=<(\w+)>).*(?=<\/\1>) (html卷标间的文字)
这使用lookahead及lookbehind assertion来取出html间的文字,不包括html卷标。
请批注(comments please)
括号还有个特殊的用途就是用来包住批注,语法为”(?#comment)”,若设定”ignore pattern whitespace”选项,则re中的空格符当re使用时会乎略。此选项设定时,”#”之后的文字会乎略。
31. html卷标间的文字,加上批注
(?<= #查找前缀,但不包含它
<(\w+)> #html标签
) #结束查找前缀
.* #符合任何文字
(?= #查找字尾,但不包含它
<\/\1> #符合所抓取群组1之字符串,也就是前面小括号的html标签
) #结束查找字尾
寻找最多字符的字及最少字符的字(greedy and lazy)
当re下要查找一个范围的重复时(如”.*”),它通常会寻找最多字符的符合字,也就是greedy matching。举例来说。
32. a.*b (开始为a结束为b的最多字符的符合字)
若有一字符串是”aabab”,使用上述re所得到的符合字符串就是”aabab”,因为这是寻找最多字符的字。有时希望是符合最少字符的字也就是 lazy matching。只要将重复前述项目的表加上问号(?)就可以把它们全部变成lazy matching。因此”*?”代表的就是重复任意 次数,但是使用最少重复的次数来符合。举个例子来说:
33. a.*?b (开始为a结束为b的最少字符的符合字)
若有一字符串是”aabab”,使用上述re第一个所得到的符合字符串就是”aab”再来是”ab”,因为这是寻找最少字符的字。
*? 重复任意次数,最少重复次数为原则
+? 重复至少一次,最少重复次数为原则
?? 重复零次或一次,最少重复次数为原则
{n,m}? 重复至少n次,但不超过m次,最少重复次数为原则
{n,}? 重复至少n次,最少重复次数为原则
还有什么没提到呢?
到目前为止,已经提到了许多建立re的元素,当然还有许多元素没有提到,下表整理了一些没提到的元素,在最左边的字段的数字是说明在expresso中的例子。
# 语法 说明
\a bell 字符
\b 通常是指字的边界,在字符组里所代表的就是backspace
\t tab
34 \r carriage return
\v vertical tab
\f from feed
35 \n new line
\e escape
36 \nnn ascii八位码为nnn的字符
37 \xnn 十六位码为nn的字符
38 \unnnn unicode为nnnn的字符
39 \cn control n字符,举例来说ctrl-m是\cm
40 \a 字符串的开始(和^相似,但不需籍由multiline选项)
41 \z 字符串的结尾
\z 字符串的结尾
42 \g 目前查找的开始
43 \p{name} unicode 字符组名称为name的字符,比如说\p{lowercase_letter} 所指的就是小写字
(?>exp) greedy次描述,又称之为non-backtracking次描述。这只符合一次且不采backtracking。
44 (?<x>-<y>exp)
or (?-<y>exp) 平衡群组。虽复杂但好用。它让已命名的抓取群组可以在堆栈中操作使用。(小弟对这个也是不太懂哩)
45 (?im-nsx:exp) 为次描述exp更改re选项,比如(?-i:elvis)就是把elvis大乎略大小写的选项关掉
46 (?im-nsx) 为之后的群组更改re选项。
(?(exp)yesno) 次描述exp视为zero-width positive lookahead。若此时有符合,则yes次描述为下一个符合标的,若否,则no 次描述为下一个符合标的。
(?(exp)yes) 和上述相同但无no次描述
(?(name)yesno) 若name群组为有效群组名称,则yes次描述为下一个符合标的,若否,则no 次描述为下一个符合标的。
47 (?(name)yes) 和上述相同但无no次描述
结论
经过了一连串的例子,及expresso的帮忙,相信各位大大对re有个基本的了解,网络上当然有许多有关于re的文章,如果各位大大有兴趣http://www.codeproject.com 还有许多关于re的相关文章。
最新评论