在程序员的修炼过程中,借鉴和修改优秀的源代码是学习编程的捷径。Google就提供了这个很方便的开源代码搜索引擎,网址:codesearch。在(三)google的codesearch里介绍
搜索关键字的语法是正则语法,首先介绍一下正则语法(regexp)的使用。我熟悉的主要开发语言是Java,所以就拿Java对正则语法的使用做为学习的扩充了。在(二)Java与正则语法中介绍
正则语法是基于正则表达式的语法,Phython、Java等开发语言对其都有支持。这是第一部分(一) 正则语法基础
在第四部分会是我用正则语法的使用经验和技巧,以及用正则语法在codesearch上搜索到的经验。
1 正则表达式的定义和作用
定义:正则表达式(regular expression)描述了一种字符串匹配的模式。没有什么难的,当然还是把定义说一下,因为定义往往很重要,而我们这些coding人却不太在意,其实对编程接触久了,就会发现交流的时候定义是最准确,最快速的让别人理解你的方式。
注意定义中的话:1)字符串,好了针对的东西知道了.2)模式,提到模式就让我想起了结构,好了字符串的结构规则的说明的东西。
2 正则表达式规则(RE)
2.1 普通字符(ordinary character)
没有特殊字符的字符串,特殊字符接下来介绍。普通字符像’A’,’a’,’0’等。普通字符仅仅match它们本身。普通字符连接起来就是字符串了。如last matches 字符串"last"
2.2 特殊字符(special character)
特殊字符 特殊字符用转义字符和它本身来代表自己
-
"." (DOT.)在缺省模式下,它匹配除了换行符(/n)newline以外任何一个字符。要匹配小数点本身,使用"/."
-
"^" (Caret.)匹配字符串的起始部分。要匹配"^"用"/^"
-
"$" 匹配字符串的结束部分或者是在换行符之前的字符串。比如foo匹配'foo'和'foobar',但正则表达式下foo$仅仅匹配'foo'.要匹配"$"用"/$"
-
"*" 简单的说就是使RE去匹配前面的RE0次或是n次,修饰匹配次数。比如ab*匹配'a','ab'和'abbbbb……b'.要匹配"*"用"/*"
-
“+” 使RE去匹配前面的RE1次或是n次,修饰匹配次数。比如ab+匹配'ab'和'abbbbb……b'.要匹配"+"用"/+"
-
“?” 使RE去匹配前面的RE0次或是1次。比如ab?匹配'a’和'b’
贪婪(greedy)模式和非贪婪(non-greedy)模式
贪婪模式就是尽可能多的匹配,用英语能更好的解释为match as much text as possible.
非贪婪模式也叫勉强模式(minimal)就是尽可能少的匹配,用英语解释为match as few character as possible。
-
*? 、+?、 ?? “*” 、“+” 、“?”都是贪婪(greedy)模式,而在贪婪模式后加”?”则为非勉强模式。如字符串”<H1>code</H1>”,RE为”<.*>”,匹配结果为”<H1>code</H1>”整个字符串,而我们有时候需要的是<H1>,那么RE为”<.*?>”非贪婪模式去匹配。
-
{m} 准确的重复先前的REm次,如a{6}匹配”a”字符6次,而不是5次。
-
{m,n} 贪婪模式,匹配尽可能多的m次至n次的RE, 如果{,n},那么m默认为0,如果{m,},那么默认n是无穷大。
-
{m,n}?非贪婪模式,匹配尽可能少的m次至n次RE,比如string ‘aaaaaa’,a{3,5}会匹配5个a,而a{3,5}?会匹配3个a.
-
“/” 转义字符,其实我们已经很熟悉了,除了我们经常见到的/n,/r,/t等等,它还表示特殊符号本身”//”,”/.”,”/^”等
-
[ ]、[ - ]和[^ ] 是用[ ]包含一系列字符,能够匹配其中任意字符。[ - ]则是一系列字符的范围的意思。[^ ]是能够匹配其中任意字符之外的RE。举例:[ab5@] 匹配 "a" 或 "b" 或 "5" 或 "@"。[^abc],匹配 "a","b","c" 之外的任意一个字符。[f-k] 匹配 "f"~"k" 之间的任意一个字母。[^A-F0-3] 匹配 "A"~"F","0"~"3" 之外的任意一个字符。
-
“|” 非贪婪模式,A|B,就是匹配A或者B,如果A已匹配,那么就不会去匹配B了。如果想要匹配字符本身,则可以用”/|”或者”[|]”来表示。
-
() 在()里的表达式可以当作整体来匹配。用”(“和”)”来匹配括号,或则用[(][)]来匹配
-
(?...)模式,在?后的字符决定扩展模式的作用
-
(?isLmsux) 设置可选参数的另类方式,不影响匹配。
ü I 或 IGNORECASE 匹配忽略时大小写。
ü L 或 LOCALE 让 /w, /W, /b, 和 /B 由当前区域设置决定。
ü M 或 MULTILINE 特殊符号 ^ 和 $ 除了匹配字符串开始和结尾,也匹配每行的开始和结尾 (换行符之后/之前)。
ü S 或 DOTALL 特殊字符 . 匹配任意字符,包括换行符 .U 或 UNICODE /w, /W, /b, 和 /B 由Unicode字符集决定
分组和捕获(Groups and Captrue)
J
ava编程时我会用到,所以还是清楚一下好在(…)内因为有嵌套括号,所以给括号分组就很有用。简单来说,捕获分组从左括号开始计数,例如在表达式((A)(B(C))),它有4个如此的分组
1.((A)(B(C)))
2.(A)
3.(B(C))
4.(C)
Group 0总是代表整个表达式
-
(?:...) 是非分组模式的()
-
(?P<id>...) 类似 (...), 但该组同时得到一个 id,可以在后面的模式中引用
-
(?P=id) 匹配前面id组匹配的东西
-
(?P<id>...) 类似 (...), 但该组同时得到一个 id,可以在后面的模式中引用
-
(?P=id) 匹配前面id组匹配的东西
-
(?#...) 括号内的内容仅仅是注释,不影响匹配
注:我在Java 里没有找到这Perl语法的支持所以用了别的编号以引起你的注意
-
(?=…)和(?!...) (positive lookahead和negative lookahead)就是匹配字符串的后面(正方向)要跟着(?=)里的内容,和匹配后面字符串不是(?!...)里的内容. 举例表达式 "Windows (?=NT|XP)" 在匹配 "Windows 98, Windows NT, Windows 2000" 时,将只匹配 "Windows NT" 中的 "Windows ",其他的 "Windows " 字样则不被匹配。"Windows (?!=NT|98)"则会匹配Windows 2000中的Windows.
-
(?<=…)和(?<!...) (positive lookbehind和negative lookbehind)是(?=…)和(?!...) 的相反方向.应该明白吧,不明白,就举例了(?<=abc)def匹配字符串abcdef中的def 而不匹配字符串defabc,同理!就是非的意思
2.3 转义字符下的特殊字符
“/..”后跟着一个字符代表新的特殊字符
-
/A 仅仅匹配字符串的开头部分
-
/b 匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符
-
/B 匹配非单词边界,即左右两边都是 "/w" 范围或者左右两边都不是 "/w" 范围时的字符缝隙
-
/b 匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符
-
/B匹配非单词边界,即左右两边都是 "/w" 范围或者左右两边都不是 "/w" 范围时的字符缝隙 /d 匹配任何10进制数字,与RE[0-9]等价
-
/D 匹配任何非10进制数字,与RE[^0-9]等价
-
/s 匹配whitespace字符,与RE[ /t/n/x0B/f/r]等价
-
/S 匹配非whitespace字符,与RE[^ /t/n/x0B/f/r]等价
-
/w 匹配word,与RE[a-zA-Z_0-9]等价
-
/W 非word,与RE[^/w]等价
-
/z 匹配字符串结束。
3 总结
写这些枯燥的基础真的是很累,我参考了一下文档,下班后写了俩个晚上,希望能有一些作用。我也列出了一下相关的正则语法参考的网站和资料。
http://www.regexlab.com/zh/
正则表达式工具室
http://docs.python.org/lib/re-syntax.html
python的doc, Regular Expression Syntax
还有java doc,我会在下一部分跟大家分享。