对于文字字符,有11个字符被保留作特殊用途。他们是:
[ ] / ^ $ . | ? * + ( )
这些特殊字符也被称作元字符
不可显示字符
可以使用特殊字符序列来代表某些不可显示字符:
<</t>>代表Tab(0x09)
<</r>>代表回车符(0x0D)
<</n>>代表换行符(0x0A)
字符集
字符集是由一对方括号“[]”括起来的字符集合。使用字符集,你可以告诉正则表达式引擎仅仅匹配多个字符中的一个。如果你想匹配一个“a”或一个“e”,使用<<[ae]>>,你可以使用<<gr[ae]y>>匹配gray或grey
你可以使用连字符“-”定义一个字符范围作为字符集。<<[0-9]>>匹配0到9之间的单个数字
<<[0-9a-fxA-FX]>>匹配一个十六进制数字或字母X。再次强调一下,字符和范围定义的先后顺序对结果没有影响
查找程序语言的标识符,<<A-Za-z_][A-Za-z_0-9]*>>。(*表示重复0或多次)
查找C风格的十六进制数<<0[xX][A-Fa-f0-9]+>>。(+表示重复一次或多次)
在左方括号“[”后面紧跟一个尖括号“^”,将会对字符集取反。结果是字符集将匹配任何不在方括号中的字符
因为一些字符集非常常用,所以有一些简写方式
<</d>>代表<<[0-9]>>;
<</w>>代表单词字符。这个是随正则表达式实现的不同而有些差异。绝大多数的正则表达式实现的单词字符集都包含了<<A-Za-z0-9_]>>。
<</s>>代表“白字符”。这个也是和不同的实现有关的。在绝大多数的实现中,都包含了空格符和Tab符,以及回车换行符<</r/n>>
使用?*或+ 进行重复
?:告诉引擎匹配前导字符0次或一次。事实上是表示前导字符是可选的。
+:告诉引擎匹配前导字符1次或多次
*:告诉引擎匹配前导字符0次或多次
如果你用“?*+”操作符来重复一个字符集,你将会重复整个字符集。而不仅是它匹配的那个字符。正则表达式<<[0-9]+>>会匹配837以及222
你可以用<</b[1-9][0-9]{3}/b>>匹配1000~9999之间的数字(“/b”表示单词边界)。<</b[1-9][0-9]{2,4}/b>>匹配一个在100~99999之间的数字
惰性扩展的一个替代方案
我们还有一个更好的替代方案。可以用一个贪婪重复与一个取反字符集:“<[^>]+>”。之所以说这是一个更好的方案在于使用惰性重复时,引擎会在找到一个成功匹配前对每一个字符进行回溯。而使用取反字符集则不需要进行回溯
“.”匹配一个单个的字符而不用关心被匹配的字符是什么。唯一的例外是新行符。在本教程中谈到的引擎,缺省情况下都是不匹配新行符的。因此在缺省情况下,“.”等于是字符集[^/n/r](Window)或[^/n]( Unix)的简写
“^”匹配一行字符串第一个字符前的位置。<<^a>>将会匹配字符串“abc”中的a。<<^b>>将不会匹配“abc”中的任何字符。
类似的,$匹配字符串中最后一个字符的后面的位置。所以<<c$>>匹配“abc”中的c
单词边界
元字符<</b>>也是一种对位置进行匹配的“锚”。这种匹配是0长度匹配
有4种位置被认为是“单词边界”:
1) 在字符串的第一个字符前的位置(如果字符串的第一个字符是一个“单词字符”)
2) 在字符串的最后一个字符后的位置(如果字符串的最后一个字符是一个“单词字符”)
3) 在一个“单词字符”和“非单词字符”之间,其中“非单词字符”紧跟在“单词字符”之后
4) 在一个“非单词字符”和“单词字符”之间,其中“单词字符”紧跟在“非单词字符”后面
“单词字符”是可以用“/w”匹配的字符,“非单词字符”是可以用“/W”匹配的字符。在大多数的正则表达式实现中,“单词字符”通常包括<<[a-zA-Z0-9_]>>
子表达式
由()包围的才算一个表达式!
子表达式(子模式,subpatterns)可以有以下作用:
1. 将多选一的分支局部化。
例如,模式: cat(aract|erpillar|)匹配了 "cat","cataract" 或 "caterpillar" 之一,没有圆括号的话将匹配 "cataract","erpillar" 或空字符串。
2. 将子模式设定为捕获子模式(例如上面这个例子)。当整个模式匹配时,目标字符串中匹配了子模式的部分可以通过逆向引用进行调用。左圆括号从左到右计数(从 1 开始)以取得捕获子模式的数。
注意,子模式是可以嵌套的,例如,如果将字符串 "the red king" 来和模式 /the ((red|white) (king|queen))/进行匹配,捕获的子串为 "red king","red" 以及 "king",并被计为 1,2 和 3 ,可以通过"/1","/2","/3"来分别引用它们,"/1"包含了"/2"和"/3",它们的序号是由左括号的顺序决定的
非捕获子模式(non-capturing subpatterns)
用一对括号同时完成上面提到的子模式的两个功能有时会出现一些问题,例如,由于逆向引用的数目是有限的(通常最大不超过9),而且经常会遇到无需捕获的子模式定义。这时,可以在开始的括号后加上问号和冒号来表示这个子模式无需捕获,就向下面这样:((?:red|white) (king|queen))。
如果将"the white queen"作为模式匹配的目标字符串,则捕获的字串有"white queen"和"queen",分别作为"/1"和"/2",white虽然符合子模式"(?:red|white)",但并不被捕获
注:
对于非捕获子模式,举个列子:
reg.Subject := '生长阶段:12%<br><font size=''12'' color=''#666666''>再过1小时48分长高一些</font><br>距离收获:1天21小时48分<br>';
reg.RegEx := '距离收获:(?:(/d+)天)?(?:(/d+)小时)?(?:(/d+)分)?(?:(/d+)秒)?';
while reg.MatchAgain do
begin
day := reg.SubExpressions[1]; //得到1天中的1
hour := reg.SubExpressions[2];//得到21小时中的21
min := reg.SubExpressions[3]; //得到48分中的48
sec:= reg.SubExpressions[4];
end;
倘若没有上述表达式中的问号加冒号?:,
则会得到day := reg.SubExpressions[1]; //得到1天即引擎认为出现了8个表达式而非四个!
hour := reg.SubExpressions[2];//得到1天中的1
min := reg.SubExpressions[3]; //得到48分
sec:= reg.SubExpressions[4]; //得到48分中的48
//提取子表达式匹配到的内容
var
reg: TPerlRegEx;
begin
reg := TPerlRegEx.Create(nil);
reg.Subject := 'abc A1111 BB222 CCC33 DDDD4';
reg.RegEx := '/b([A-D]+)([1-4]+)/b'; //这个表达式有两个子表达式构成
while reg.MatchAgain do
begin
ShowMessage(reg.SubExpressions[0]); //将分别显示: A1111 BB222 CCC33 DDDD4
ShowMessage(reg.SubExpressions[1]); //将分别显示: A BB CCC DDDD
ShowMessage(reg.SubExpressions[2]); //将分别显示: 1111 222 33 4
再比如
reg.RegEx := '<div class=/"l/" style=/"width:8em;/"><a href=/"javascript:gotoUser/(([^<]+)/);/" class=/"sl/">([^<]+)</a></div>';
正因为有了2对(),所以以下调用才能成功
Text := Text + reg.SubExpressions[1] + #13 ;//表示第一对()内的值1608336
Text := Text + reg.SubExpressions[2] + #13 ;//表示第二对()内的值
上述例子援引自Jailu的开源项目
http://code.google.com/p/kaixin001-helper/