⑥ 选择、分组和引用
正则表达式的语法还包括指定选择项、对子表达式分组和引用前一子表达式的特殊字符。字符"|"用于分隔供选择的字符。例如,/ ab|cd|ef /匹配的是字符串“ab”,或者是字符串“cd”,又或者是字符串“ef”。/ \d{3}|[a-z]{4} /匹配的是三位数字或四个小写字母。
注意,选择项是从左到右考虑的,直到发现了匹配项。如果左边的选择项匹配,就忽略右边的匹配项,即使它产生更好的匹配。因此把模式/ a|ab /应用到字符串"ab"上时,它只匹配第一个字符。
在正则表达式中括号具有几种作用。
⑴ 把单独的项目组合成子表达式,以便可以像处理一个独立的单元那样用|,*,+或?等来处理它们。例如/ java(script)? /匹配的是字符串“java”,其后既可以有“script”,也可以没有。/ (ab|cd)+|ef /匹配的既可以是字符串“ef”,也可以是字符串“ab”或者“cd”的一次或多次重复。
⑵ 在完整的模式中定义子模式。当一个正则表达式成功地和目标字符串相匹配时,可以从目标串中抽出和括号中的子模式相匹配的部分。例如假定我们正在检索的模式是一个或多个小写字母后面跟随了一位或多位数字,则可以使用模式/ [a-z]+\d+ /。但是假定我们真正关心的是每个匹配尾部的数字,那么如果将模式的数字部分放在括号中(/ [a-z]+(\d+)/ ),就可以从所检索到的任何匹配中抽取数字了,之后我们会对此进行解释。
⑶ 括号允许我们在同一正则表达式的后部引用前面的子表达式,这是通过在字符"\"后加一位或多位数字实现的,数字指定了带括号的子表达式在正则表达式中的位置。例如,\1引用的是第一个带括号的子表达式,\3引用的是第三个带括号的子表达式。注意由于子表达式可以被嵌套在别的子表达式中,所以它的位置是被计数的左括号的位置。例如在下面的正则表达式中,嵌套的子表达式([Ss]cript)就被指定为\2。
/ ([Jj]ava([Ss]cript)?)\sis\s(fun\w*) /
对正则表达式中前一子表达式的引用所指的并不是那个子表达式的模式,而是与那个模式相匹配的文本。这样,引用可以用于实施一条约束,即一个字符串各个单独的部分包含的是完全相同的字符。例如下面的正则表达式匹配的就是位于单引号或双引号之内的0个或多个字符。但是,它并不要求开始和结束的引号匹配(例如两个都是双引号或者两个都是单引号):
/[' "][^ ' "]*[' "]/
如果要求开始和结束的引号相匹配,可以使用如下的引用:
/([' "])[^ ' "]*\1/
\1匹配的是第一个带括号的字表达式所匹配的模式的文本。在这个例子中,它实施了一条约束,那就是开始的引号必须和结束的引号相匹配。正则表达式不允许用双引号括起的字符串中有单引号,反之亦然。在字符类中使用引用是不合法的,所以我们不能编写:
/([' "])[^ \1]*\1/
在后续文章中,我们会看到一种对带括号的子表达式的引用,它们是对正则表达式进行检索和替换操作的强大特性之一。
在JavaScript 1.5中,无需创建带编码的引用就可以将正则表达式中的项目进行组合。它不是以“(”和“)”对项目进行分组,而以“(?:”和“)”来分组。考虑如下的模式:
/([Jj]ava(?:[Ss]cript)?)\sis\s(fun\w*)/
这里子表达式(?:[Ss]cript)仅仅用于分组,因此复制符号“?”可以应用到各个分组。这种改进了的括号并不生成引用,所以在这个正则表达式中,\2引用了与(fun\w*)匹配的文本。下表总结了正则表达式的选择、分组和引用运算符:
字符 | 含义 |
| | 选择。匹配的是该符号左边的子表达式或右边的子表达式 |
(...) | 组合。将几个项目组合为一个单元,这个单元可由*、+、?和|等符号使用,而且还可以记住和这个组合匹配的字符以供此后的引用使用。 |
(?:...) | 只组合。把项目组合到一个单元,但是不记忆与该组匹配的字符。 |
\n | 和第n个分组第一次匹配的字符相匹配。组是括号中的子表达式。组号是从左到右计数的左括号数,以(?:形式分组的组不编码。 |