常规表达式

注: 本章节内容根据有奇趣科技公司提供的文件改编。

简介

常规表达式,即"regexps",是一种在文本中查找模式的方法。此功能在许多场合中都很有用,例如,可以使用常规表达式确认一篇文本是否符合一定的标准。Switch 中,一个常规表达式可基于一些命名架构整理文件:仅文件名与常规表达式匹配的文件才能以特定连接通过。

尽管几乎可以肯定对常规表达式在 Switch 中的应用没有影响,但应知道并非所有常规表达式实现在创建时并非相同。大多实现都为基本表达式提供相同的结果,但是一些更高级的表达式的结果与匹配会有些微差别。

Switch 的常规表达式语言以 Perl 的常规表达式语言为模板。关于常规表达式,Jeffrey E. Friedl所著的 Mastering Regular Expressions: Powerful Techniques for Perl and Other Tools(国际标准图书编号:1565922573)可供参考。多个网站为使用常规表达式提供工具,或者为匹配各种样式提供样例库。您可访问 http://www.roblocher.com/technotes/regexp.aspx,获取一个使用常规表达式的简单工具。

简单教程

常规表达式由表达式、限定符和判断提示组成的。表达式最简单的形式是一个字符。例如,x5。一个表达式也可是一个字符集。例如,[ABCD] 可和 ABCD 匹配。此数据集可简写成 [A-D]。如需要匹配到英文字母表中的所有字母,可使用 [A-Z]。限定符为常规表达式引擎指定了表达式的出现次数。例如,x{1,1} 指匹配 x 至多一次,至少一次。后面再讨论判断提示与更复杂的表达式。

首先,写一个常规表达式以匹配 0 到 99 内的整数。因为至少需要一个数字,所以首先写下 [0-9]{1,1} 表达式,指匹配一个数字一次。如只有常规表达式,则匹配 0 到 9 内的整数。如需匹配一个或两个数字,可增加最大出现次数,因此,常规表达式变成 [0-9]{1,2},指匹配一个数字至少一次,至多两次。事实上,该常规表达式无法正确匹配。它可匹配一个字符串内一个或两个数字。为保证匹配范围是整个字符串,必须使用锚判断提示。以^(脱字符号)为常规表达式的第一个字符时,表示必须从字符串的开头开始匹配。 以$(美元符号)为常规表达式最后一个字符时,表示必须一直匹配到字符串的末尾。因此,常规表达式应写成 ^[0-9]{1,2}$。注意,判断提示(如 ^ 和 $)不与任何字符匹配。

其他地方的常规表达式可能与上述的常规表达式不同。

因为一些常用的字符集和限定符以特殊符号来表示。可用 \d 代替 [0-9]

指定值匹配一次的{1,1}限定符可用表达式本身代替。即 x{1,1}x 实际上是相同的。因此,上述匹配 0 到 99 的常规表达式可写成 ^\d{1,2}$。也可写成^\d\d{0,1}$,即从字符串的开头开始匹配一个数字 后跟 0 个或 1 个数字。实际上,大多数人会将其写成 ^\d\d?$? {0,1} 限定符的简写,表示至少出现 0 次,至多出现 1 次。该限定符可设置表达式匹配项的次数。^\d\d?$常规表达式表示从字符串的开头到字符串的末尾,匹配一个数字 后跟 0 个或 1 个数字。

第二个例子,匹配"mail"、"letter"或"correspondence"而不匹配"email"、"mailman","mailer"和"letterbox"等。首先,从仅匹配"mail"开始。完整的常规表达式如下:m{1,1}a{1,1}i{1,1}l{1,1}。但是由于每一个表达式自动限定为{1,1},可写成 mailm 后跟 a 再跟 i 再跟 l。符号|(竖杠)用于交替。因此,常规表达式变成 mail|letter|correspondence,表示匹配"mail","letter"或"correspondence"。然而,该表达式会匹配到我们不需要的单词,例如 "email"。

首先,为常规表达式加上括号:(mail|letter|correspondence)

括号有两个作用。第一,将表达式聚在一起;第二,识别常规表达式中捕获作后续使用的部分。常规表达式仍可匹配三个词中的任意一个,只是现在作为一个整体。这有助于创建更复杂的常规表达式。还能查出实际匹配的单词。

另一个判断提示为\b "单词边界": \b(mail|letter|correspondence)\b

该常规表达式表示"匹配一个单词边界后跟带括号的表达式再跟另一个单词边界"。\b判断提示匹配常规表达式中的一个位置而不是一个字符。单词边界为任意非单词字符,例如空格、换行符或一个字符串的开头或末尾。

字符集的字符和简写

元素

含义

c

所有字符均代表其本身,除非有特殊的常规表达式含义。因此,c 匹配字符 c。

\c

一个反斜杠加一个字符,表示匹配字符本身,下述情况除外。例如,如需匹配一个位于字符串开头的脱字符号,写成 \^。

\a

匹配 ASCII 报警符号 (BEL、0x07)。

\f

匹配 ASCII 换页字符 (FF、0x0C)。

\n

匹配 ASCII 换行字符 (LF、0x0A、Unix 换行符)。

\r

匹配 ASCII 回车字符 (CR、0x0D)。

\t

匹配 ASCII 水平制表符 (HT、0x09)。

\v

匹配 ASCII 垂直制表符 (VT, 0x0B)。

\xhhhh

匹配对应十六进制数字 hhhh的 Unicode 字符(在0x0000 和 0xFFFF之间)。

\0ooo

(即零 ooo)匹配与八进制数字 ooo 对应的 ASCII/Latin1 字符(0到0377之间)。

.

(即句号)匹配任何字符(包括换行符)。

\d

匹配一个数字。

\D

匹配一个非数字。

\s

匹配一个空格。

\S

匹配一个非空格。

\w

匹配一个单词字符(字母/数字或下划线)。

\W

匹配一个非单词字符。

\n

匹配第 n 个反向引用。例如,\1,\2等。

字符集

方括号用于匹配方括号里字符集中任意字符。所有上述字符集的简写可在方括号内使用。除字符集简写和以下两个例外,方括号中的字符没有特殊含义。

字符

含义

^

如脱字符号作为第一个字符出现,即紧跟开方括号,则该脱字符号否定字符集。例如,[abc] 表示匹配"a"或"b"或"c",而[^abc]表示匹配除"a"或"b"或"c"以外的任何字符。

-

破折号表示一定范围的字符。例如,[W-Z] 匹配"W"或"X"或"Y"或"Z"。

使用预设定的字符集简写比使用横跨平台和语言的字符范围更方便。例如,[0-9]匹配西方字母表中的一个数字,而\d 匹配任何字母表中的一个数字。

注意,在大多常规表达式文献中,字符集通常叫作"字符类"。

限定符

默认情况下,一个表达式自动限定为 {1,1},即出现次数为 1。在下表中,E 表示任意表达式。一个表达式是一个字符或一个字符集的简写或包含在方括号内的字符集或任意带括号的表达式。

限定符

含义

E?

E 的匹配次数为0或1。该限定符表示"前一个表达式可选",因为它会匹配该表达式是否在字符串中出现。与 E{0,1}的效果一样。例如,dents?将会匹配"dent"和"dents"。

E+

E 的匹配次数为一次或多次,与 E{1,} 的效果相同。例如,0+ 会匹配"0","00",和"000"等。

E*

E 的匹配次数为零次或多次,与 E{0,}的效果相同。限定符*常被误用。因为匹配零次或多次,的结果可能是匹配零次。例如,使用 \s*$ 常规表达式匹配以空格结束的字符串时,可能会匹配到每一个字符串。是因为指定了查找字符串末尾后跟零个或多个空格,所以即使是不以空格结尾的字符串都会匹配到。这种情况下,需使用\s+$常规表达式,匹配末尾至少有一个空格的字符串。

E{n}

E 的匹配次数为 n 次,与重复表达式 n 次效果相同。例如,x{5}xxxxx 效果相同。也与 E{n,n} 的效果相同,例如 x{5,5}

E{n,}

E 匹配至少 n 次。

E{,m}

E 匹配至多 m 次,与 E{0,m}效果相同。

E{n,m}

E 匹配至少 n 次,至多 m 次。

如需将把某一限定符应用于上述字符之外,可用括号将字符聚到一个表达式。例如,tag+表示匹配"t"后跟"a"再跟至少一个"g",而(tag)+至少会匹配到一次"tag"。

限定符是贪婪的。它们会尽可能多地匹配文本。例如,0+ 就会从第一个发现的0开始尽可能多地匹配0。例如,2.0005。

捕获文本

使用括号可将元素聚在一起以量化并捕获文本。例如,在 mail|letter|correspondence 表达式中,我们知道会匹配其中一个单词,但不知道是哪一个。通过使用括号,我们可捕获任何在它们范围内匹配的单词。因此,将 (mail|letter|correspondence) 常规表达式用在"I sent you some email"字符串,则捕获到"mail"。

我们可将捕获到的文本用在此常规表达式。使用从1开始索引的反向引用,以查找捕获到的文本。例如,可用 \b(\w+)\W+\1\b 在一个字符串中搜索复制文字。该表达式匹配一个单词边界后跟上一个或多个单词字符再跟一个或多个非单词字符再跟与第一个带括号表达式相同的文本再跟一个单词边界。

如我们只需使用括号的聚集功能而非捕获功能,可使用非捕获性的语法,如(?:green|blue)。非捕获性的括号以"(?:"开头以")"结尾。在上例中,匹配"绿色"或者"蓝色",但不捕获匹配。因此,我们只知道是否匹配,但不知道匹配到的是哪种颜色。因为常规表达式引擎在非捕获性匹配过程中较少记录,所以使用非捕获性括号比使用捕获性括号的效率高。

捕获性和非捕获性的括号均可嵌套。

锚可匹配字符串的开头或者结尾,但不匹配任何字符。

输入 Switch 用户界面的常规表达式始终匹配整个字符串。换言之,常规表达式自动从字符串开始固定到字符串末尾,不得指定确切的锚。(如有需要,在 Switch JavaScript 程序中指定的常规表达式应包含确切的锚)。

含义

^

脱字符号表示字符串的开头。如要匹配一个字面的 ^,应写成 \^ 以跳过它。例如,^#include 表达式只会匹配到由"#include"开头的字符。(如脱字符号是字符集的第一个字符,则具有特殊意义。详情请参阅"字符集"。)

$

美元符号表示字符串的结尾。例如,\d\s*$可匹配以一个数字结尾的字符串,后跟空格或不跟空格。如要匹配一个字面的 $,应写成 \$ 以跳过它。

判断提示

判断提示通过其在常规表达式出现的点上对文本做陈述,但不匹配任何字符。在下表中,E 表示任意表达式。

判断提示

含义

\b

单词边界。例如,\bOK\b常规表达式表示在单词边界(例如:字符串开始或空格)之后匹配字母"O",然后在另一个单词边界(例如:字符串末尾或空格)之前匹配"K"。注意,判断提示实际不匹配任何空格。因此,如常规表达式为 \bOK\b且有匹配,结果只会包含"OK"即使字符串是"It's OK now"。

\B

非单词边界。\b为假,则判断提示为真。如在"Left on"搜索\Bon\B,则匹配失败(空格和字符的结尾并不是非单词边界),但是在"tonne"中搜索就会匹配成功。

(?=E)

肯定性先行断言。如表达式在常规表达式该点上匹配成功,则判断提示为真。例如,const(?=\s+char) 匹配"const",只要后跟"char",如在"static const char *"中一样。(与"static const char *"匹配const\s+char进行对比。)

(?!E)

否定性先行断言。如表达式在常规表达式该点上匹配失败,则判断提示为真。例如,const(?!\s+char) 匹配"const",只要不后跟"char"。

注: 目前不支持肯定性和否定性的后行断言。

不区分大小写匹配

使用 /.../i 结构包围整个常规表达式使其不区分大小写。更具体地说,如常规表达式以前斜线开头,以前斜线加字母 i 结尾,则整个表达式的匹配不区分大小写。

例如:

常规表达式

匹配下列字符串

ABC

ABC

abc

abc

/ABC/i

ABC,abc,Abc

/ABC/

/ABC/