[跟我学正则表达式] 4. 使用元字符

2009年4月30日星期四

[跟我学正则表达式] 4. 使用元字符

在第二章“匹配单个字符”中引入了元字符,在本章中将学习到更多的元字符,用来匹配其他特定的字符或者字符类型。

再看转义
在深入到元字符的世界之前,理解字符转义是很重要的。
元字符是在正则表达式中有着特殊含义的字符。“.”是元字符,用来匹配一个特定的字符。同样的,“[”也是一个元字符,被用来标记字符组的开始。
因为元字符在正则表达式中有着特殊的意义,所以这些字符不能直接表示自己的含义。例如,不能使用“[”来匹配“[”,使用“.”来匹配“.”。看看下面的例子,一个正则表达式被用来匹配包含了“[”和“]”的Javascript数组:
文本
varmyArray=newArray();
...
if(myArray[0]==0){
...
}
正则表达式
myArray[0]

结果
varmyArray=newArray();
...
if(myArray[0]==0){
...
}

分析
在这个例子中,文本为一个Javascript的代码块。这里的正则表达式则是你将在文本编辑器中可能使用的类型。本来是期望能够匹配文本myArray[0],但是实际上不能。为什么?因为“[”和“]”是用来定义字符组的正则表达式元字符。这个正则表达式是在myArray后接上字符组的一个成员,而这个成员只有0,所以这个正则表达式myArray[0]将唯一匹配myArray0。

就像在第二章中解释的一样,元字符可以通过前面加上反斜线来转义。因此,“\.”将匹配“.”,“\[”将匹配“[”。所有的元字符都可以在前面加上反斜线转义,当转义后,字符将匹配自身而不是其特殊含义。为了能够匹配“[”和“]”,这些字符必须转义。下面是同样的例子,并使用了转义的元字符:
文本
varmyArray=newArray();
...
if(myArray[0]==0){
...
}

正则表达式
myArray\[0\]

结果
varmyArray=newArray();
...
if(myArray[0]==0){
...
}

分析
现在这个搜索可以工作了。“\[”匹配“[”,“\]”匹配“]”,所以myArray\[0\]将匹配myArray[0]。

在这个例子中使用正则表达式可能是没有必要的——因为一个简单的文本搜索就足够了且更加简单。但是想象一下你不仅需要匹配myArray[0],还有myArray[1]和myArray[2]等。这时候使用正则表达式将比较有意义。可以通过转义“[”和“]”并指定其中需要匹配的字符。假设你需要匹配元素0到9,可以使用下面的正则表达式:
myArray\[[0-9]\]
提示:任何元字符而不仅仅是这里提到的,都可以通过前加上反斜线来转义。
注意:作为成对存在的元字符(如[和]),如果不作为元字符使用则必须转义,否则正则表达式分析器将报错。
“\”用来转义元字符,这也意味着“\”也是一个元字符:用来转义其他字符。就像第二章中说到的一样,如果需要“\”,可以使用“\\”。
看看下面这个简单的例子。文本是使用反斜线的文件路径(在DOS和Windows下)。现在假设你需要在Linux或者Unix下使用此路径,首先需要定位所有的反斜线:
文本
\home\ben\sales\

正则表达式
\\

结果
\home\ben\sales\

分析
“\\”匹配“\”,并找到了四个匹配。如果仅仅只是在正则表达式中使用“\”,将会遇到错误(因为正则表达式解析器将认为你的表达式是不完整的。总之,正则表达式中的“\”后需要接一个字符)。

匹配空格字符
元字符可以分为两类:一类是用来匹配文本(如“.”),另一类是正则表达式语法的一部分(如“[”和“]”)。这两种类型都有很多的元字符。本节中将首先介绍空格元字符。
在执行正则表达式搜索的时候,你可能需要匹配文本中不能打印的空白字符。例如,你希望能够找到所有的Tab字符,或者是所有的换行符。因为在正则表达式中直接输入这些字符将比较困难,你可以使用在表4.1中列出的特殊元字符。

元字符
描述
[\b]
退格符
\f
换页符
\n
换行
\r
回车
\t
制表符
\v
垂直制表符
表4.1.空白元字符

让我们来看一个例子。下面的文本快中包含了一系列用逗号隔开的纪录(一般称为CSV)。在处理这些记录之前,需要将数据中的空行删除。
文本
"101","Ben","Forta"
"102","Jim","James"

"103","Roberta","Robertson"
"104","Bob","Bobson"

正则表达式
\r\n\r\n

结果
"101","Ben","Forta"
"102","Jim","James"

"103","Roberta","Robertson"
"104","Bob","Bobson"

分析
“\r\n”将匹配一个回车换行组合,在Windows中表示一个文件换行。“\r\n\r\n”将匹配两个文件换行,因此两个记录中的空行将会标记出来。

提示:这里使用了“\r\n”作为文件换行的标志。尽管如此,在Linux和Unix系统中,仅仅只是使用了换行符。在这些系统中,只需要使用“\n”(不是“\r”)即可。理想的正则表达式时可以兼容这两种情况——一个可选的“\r”和一个必须的“\n”。在下一章中将重新来看这个例子。
这里常用的包括\r、\n和\t。而其他的空白元字符一般比较少用。

现在你已经看到了大量的元字符。“.”和“[”如果不转义的话都是元字符。而f和n,只有在转义的时候才是元字符,在不转义的时候,它们都是匹配自身的字面字符。

匹配特定的字符类型
到现在为止,你已经看到了如何匹配特定的字符:任何字符(“.”),字符集合中的一个(“[”和“]”),取消匹配字符(“^”)。字符集合(匹配集合中的一个)是最常用的匹配,所以有特殊的元字符用来匹配常用的字符集合。这些元字符被称为匹配字符类。这些元字符并不一定真正需要(总是可以枚举需要的字符),但是你将发现使用它们是很方便的。
注意:在下面列出的类元字符是在大部分正则表达式实现中支持的。

匹配数字(非数字)
在第三章中知道,[0-9]是[0123456789]的简写,可以匹配所有的数字。如果不想匹配任何数字,则可以使用[^0-9]。表4.2中列出了数字和非数字的类元字符。

元字符
描述
\d
任何数字(同[0-9])
\D
任何非数字(同[^0-9])
表4.2.数字的元字符

为了掩饰这些元字符的使用方法,下面是前一个例子的修订版:
文本
varmyArray=newArray();
...
if(myArray[0]==0){
...
}
正则表达式
myArray\[\d\]

结果
varmyArray=newArray();
...
if(myArray[0]==0){
...
}

分析
“\[”匹配“[”,“\d”匹配所有的数字,and“\]”匹配“]”,所以myArray\[\d\]匹配了myArray[0]。myArray\[\d\]是myArray\[0-9\]的简写,也是myArray\[0123456789\]的简写。这个正则表达式同样将匹配myArray[1]、myArray[2]等,但是不会匹配myArray[10]。

提示:就像你所看到的,对于一个正则表达式几乎都有多种形式。选择最喜欢的一种即可。
注意:正则表达式是区分大小写的。\d匹配数字,而\D匹配非数字。这和下面看到的其他类元字符是一样的。这在执行不区分大小写匹配的时候也是适用的,在这种情况下匹配的字符将不区分大小写,但是特殊的字符(如\d)将会区分。

匹配字母字符(非字母字符)
另外一个常用的字符集合是所有的文字数字式字符,从A到Z(包括大写和小写)、所有的数字和下划线(一般用于文件或者目录名、应用程序变量、数据库对象名等)。表4.3列出了这些文字数字式字符和非文字数字式字符的类元字符。

元字符
描述
\w
所有的文字数字式字符:大小写字母、数字和下划线(同[a-zA-Z0-9_])
\W
所有的非文字数字式字符(同[^a-zA-Z0-9_])
表4.3.文字数字式字符的元字符

下面的例子是数据库的节选,包含了US和加拿大的邮政编码:
文本
11213
A1C2E3
48075
48237
M1B4F2
90046
H1H2H2

正则表达式
\w\d\w\d\w\d

结果
11213
A1C2E3
48075
48237
M1B4F2
90046
H1H2H2

分析
这里的模式组合了“\w”和“\d”元字符用来仅仅获取加拿大的邮政编码。

注意:这里的例子应该可以工作,但是是正确的吗?想一想。为什么US的邮政编码不能匹配?因为都是由数字组成的,还有其他原因吗?我不打算给出这个问题的答案,因为这个模式可以工作。关键的是很少有正确或者错误的正则表达式(当然都可以工作)。一般说来,对于不同要求的字符串匹配有不同的正则表达式。

匹配空白(非空白)
最后一个将要遇到的匹配类是空白类。在本章的前面,已经学习到了特定空白的元字符。表4.4中列出了用来表示所有这些空白的类元字符。

元字符
描述
\s
所有的空白字符(同[\f\n\r\t\v])
\S
所有的非空白字符(同[^\f\n\r\t\v])
表4.4.空白字符的元字符

注意:[\b](退格元字符),不在\s中包含也不在\S中取消匹配。

指定十六进制和八进制值
你看你没有发现有什么方法可以表示一个特定字符的八进制或者十六进制,但是这实际上是可行的。

使用十六进制值
十六进制数字可以通过前加\x而得到。因此,\x0A(ASCII值10,换行符)实际上和\n的功能是一样的。

使用八进制值
八进制可以通过前加\0得到。因此,\011(ASCII值9,制表符)和\t的功能是一样的。

注意:许多的正则表达式实现都允许通过\c来指定控制字符。例如,\cZ将匹配Ctrl+Z。在实践中,你可能发现这个语法很少用到。

使用POSIX字符类
这是介绍各种字符集合的元字符的章节,如果不介绍POSIX字符类是不完整的。这是大部分正则表达式实现中所支持的另外一种简写形式。
注意:JavaScript的正则表达式中不支持这种POSIX字符类。


描述
[:alnum:]
任何字母和数字,(同[a-zA-Z0-9])
[:alpha:]
任何字母(同[a-zA-Z])
[:blank:]
空格或者制表符(同[\t])
[:cntrl:]
ASCII控制字符(从ASCII0到31和ASCII127)
[:digit:]
任何数字(同[0-9])
[:graph:]
和[:print:]相同但没有空白符
[:lower:]
所有的小写字母(同[a-z])
[:print:]
所有的可打印字符
[:punct:]
不在[:alnum:]和[:cntrl:]中的其他字符
[:space:]
所有的空白类字符,包括空白符(同[\f\n\r\t\v])
[:upper:]
所有的大写字母(同[A-Z])
[:xdigit:]
所有的十六进制数字(同[a-fA-F0-9])
表4.5.POSIX字符类

POSIX语法和以前看到的元字符很不相同。为了演示POSIX类的用法,我们再来看看前一章中的例子。这个例子中使用了正则表达式在一段HTML代码中定位RGB值。
文本
BODYBGCOLOR=""TEXT=""
MARGINWIDTH="0"MARGINHEIGHT="0"
TOPMARGIN="0"LEFTMARGIN="0"

正则表达式
#[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]
结果
BODYBGCOLOR=""TEXT=""
MARGINWIDTH="0"MARGINHEIGHT="0"
TOPMARGIN="0"LEFTMARGIN="0"

分析
在前面一章中使用的模式将要重复字符组[0-9A-Fa-f]六次。这里使用[[:xdigit:]]替代了[0-9A-Fa-f]。结果是一样的。

笔记:这里的正则表达式开始于“[[”并结束于“]]”。在POSIX类中这是很重要和必需的。POSIX类是通过“[:”和“:]”包裹起来的。所以使用POSIX的时候是[:xdigit:](而不是“:xdigit:”)。外层的“[”和“]”用来定义字符集合;内层的“[”和“]”则是POSIX类的一部分。

注意:这里介绍的所有12个POSIX都在支持POSIX的实现中得到支持。但是,可能会有一些细微的差异。

小结

0 评论:

发表评论