2009年4月29日星期三

[跟我学正则表达式] 2. 匹配单个字符

在本章中,我们将学到如何对一个或者更多的字符执行简单的字符匹配。

匹配文本字符
Ben就是一个正则表达式。因为这是一个普通的文本,所以看起来可能不像是正则表达式,但是事实上确实是。正则表达式可以包含普通的文本(甚至是只包含普通的文本)。无可否认,这是正则表达式处理的极大浪费,但是可能确实一个学习的起点。
下面是个例子:
文本
Hello,mynameisBen.Pleasevisit
mywebsiteat.
正则表达式
Ben
结果
Hello,mynameisBen.Pleasevisit
mywebsiteat.
分析
这里的正则表达式是文本常量,匹配了原始文档中的Ben。
让我们看看另外一个例子,使用了同样的文本和不同的正则表达式
文本
Hello,mynameisBen.Pleasevisit
mywebsiteat.
正则表达式
my
结果
Hello,mynameisBen.Pleasevisit
mywebsiteat.
分析
my同样是静态文本,但是注意到这里匹配了两次。

有多少匹配?
大多少正则表达式引擎的默认行为仅仅是返回第一个匹配。在上面的例子中,第一个my将会被匹配,而不是第二个。但是为什么会有两个匹配呢?许多的正则表达式实现都提供了一个获取所有匹配的机制(通过一个数组或者特定的格式返回)。在Javascript中,可以通过一个额外的标志g(global)来获取所有的匹配。
参考附录A:流行应用和语言中的正则表达式,学习如何在你的工具或者语言中执行全局查找。

处理大小写
正则表达式是大小写敏感的,所以Ben不会匹配ben。尽管如此,大部分的正则表达式实现都提供了一个选项是否使得匹配大小写不敏感。Javascript用户,可以通过指定i标志来使得搜索的时候是大小写不敏感的。
同样的参考附录A来看看你的语言和工具如何执行大小写不敏感的查找操作。

匹配任意字符
到现在为止正则表达式还只是能够匹配静态文本。这看起来真有点虎头蛇尾。下面我们看看如何匹配动态的字符。
在正则表达式之中,特殊的字符(有一组特殊字符)可以用来指示需要搜索的字符。“.”(句号)用来匹配任意字符。
如果你曾经使用过DOS的文件搜索,正则表达式"."的含义和DOS中的“?.”是一样的。而SQL用户则应该知道和SQL中的“_”(下划线)一样。
所以,使用“c.t”进行搜索将匹配cat和cot(以及另外一些可能无意义的前后为“c”“t”的单词)。
下面是一个例子:
文本
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
正则表达式
sales.
结果
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
分析
这里的正则表达式“sales.”用来查找以“sales”开头并后跟一个任意字符的文本。可以看到,九行中有三行匹配这个模式。
你可能会注意到有时候我们使用“模式”来描述真正的正则表达式。
注意到正则表达式匹配文本中的内容。匹配一般不是整个字符串,而是匹配此模式的文本,尽管这一半是一个字符串的一部分。在上面的例子中,正则表达式并没有匹配整个文本文件,而是匹配了其中的一部分。在将正则表达式匹配结果传递给其他代码或者应用程序处理的时候这点区别很重要。“.”可以用来匹配任意的字符、字母表中的字母,数字,甚至是“.”本身。
文本
sales.xls
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
正则表达式
sales.
结果
sales.xls
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
分析
示例中包含一个sales.xls文件,此文件可以被正则表达式“sales.”所匹配,因为“.”匹配任意一个字符。
多个“.”可以一起使用,包括放在一起(使用“..”可以匹配任意两个字符)或者用于模式中的不同地方。
让我们来看看另外一个例子。现在要找的可能是"na"或者"sa"而且不管后面跟着的是什么字符:
文本
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
正则表达式
.a.
结果
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
分析
正则表达式“.a.”不但匹配了na1、na2和sa1,还找到了没有预计到的其他匹配。为什么?因为这个模式是匹配所有中间字母为a的三个字符。
在“.a.”后面加上一个“.”会如何?下面是一个尝试:
文本
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
正则表达式
.a..
结果
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
分析
可以看到,“.a..”并不比“.a.”要好多少。加上了一个“.”符号只是多匹配了一个字符。由于“.”是一个特殊字符,当需要搜索“.”符号的时候如何办呢?

匹配特殊字符
“.”在正则表达式中含有特殊的意义。如果你需要在模式中使用“.”,你应该明确的告诉正则表达式你想使用的是一个真正的“.”字符,而不是有着特殊含义的“.”字符。为了做到这点,可以在“.”前面加上反斜线“\”对字符进行转义。这里的“\”也是特殊字符,和其本身的含义是不同的,可以对特殊字符起到转义作用。因此,“.”可以表示任意字符,而“\.”则表示真正的“.”字符。
再来看看上面的例子,这次使用“\.”替代“.”。
文本
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
正则表达式
.a.\.xls
结果
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
分析
“.a.\.xls”解决了这个问题。第一个“.”匹配了“n”或者“s”。第二个“.”匹配了“1”或者“2”,而“\.”则使用真正的“.”字符匹配了文件名和扩展的分隔符,xls匹配其自身。事实上,不加上xls也可以解决问题,这里加上的原因主要是为了避免匹配如"sa3.doc"类似的文档。
在正则表达式中,“\”总是用于一个或者多个有着特殊字符的含义之前,从而取消其特殊含义。这里看到了“\.”的使用,在以后将会看到更多利用“\”的例子。
就像你所想象的一样,转义“\”的方法就是使用两个反斜线“\\”。
另外,“.”匹配所有字符吗?可能并不正确。在很多的正则表达式实现中,“.”匹配除了换行符以外的其他字符。

小结

没有评论:

发表评论