JavaScript中的正则表达式
以下内容是来自《JavaScript权威指南(第六版)》正则表达式的模式匹配章节的笔记。
定义
JavaScript中的正则表达式定义有两种方式:
- var pattern = /s$/; 或者
- var pattern = new RegExp('s$');
直接量字符
- 所有字母和数字都是按照字面含义进行匹配
- 非字母的字符匹配,使用反斜线 \ 。如下表
字符 | 匹配 |
---|---|
字母和数字字符 | 自身 |
\o | NUL字符(\u0000) |
\t | 制表符(\u0009) |
\n | 换行符(\u000A) |
\v | 垂直制表符(\u000B) |
\f | 换页符(\u000C) |
\r | 回车符(\u000D) |
\xnn | 由十六进制数nn指定的拉丁字符,例如\x0A等价于\n |
\uxxxx | 由十六进制数xxxx指定的Unicode字符,例如\u0009等价于\t |
\cX | 控制字符^X,例如,\cJ等价于换行符\n |
字符类
将直接量字符单独放进方括号内就组成了字符类
例如 [abc] 匹配a或者b或者c
可以使用 ^ 表示否定
可以使用连字符表示范围 [a-zA-Z0-9]
某些字符很常用,所以用简练的方式来表示,下表:
字符 | 匹配 |
---|---|
[…] | 方括号内的任意字符 |
[^…] | 不在方括号内的任意字符 |
. | 除换行符和其他Unicode行终止符之外的任意字符 |
\w | 任何ASCII字符组成的单词,等价于[a-zA-Z0-9] |
\W | 任何不是ASCII字符组成的单词,等价于[^a-zA-Z0-9] |
\s | 任何Unicode空白字符 |
\S | 任何非Unicode空白字符,注意\w和\S不同 |
\d | 任何ASCII数字,等价于[0-9] |
\D | 任何ASCII数字之外的字符,等价于[^0-9] |
[\b] | 退格直接量(特例) |
注:\b有特殊的含义,见下文,若要表示退格直接量,需要中括号。[\b]
重复
语法见下表:
字符 | 含义 |
---|---|
{n,m} | 匹配前一项至少n次,但不超多m次 |
{n,} | 匹配前一项至少n次或更多次 |
{n} | 匹配前一项n次 |
? | 匹配前一项0或1次,等价于{0,1},也就说是前一项是可选的 |
+ | 匹配前一项1次或多次,等价于{1,} |
* | 匹配前一项0次或多次,等价于{0,} |
非贪婪的重复
上表列出的匹配重复字符是尽可能多的匹配,而且允许后续的正则表达式继续匹配,因此我们称之为贪婪的。若要进行非贪婪的匹配,只需在带匹配的字符后面跟一个问号 ? 即可: ?? 、 +? 等等。
选择、分组和引用
- 字符
|
用来分割供选择的字符,类似于或。注:选择项的尝试匹配顺序是从左到右,直到发现了匹配项。如果左边的选择项匹配,就忽略后边的匹配项,即使有更好的匹配。
- 分组引用使用圆括号
()
三个作用:
-
把单独的项组合成表达式,以便可以像处理一个独立单元那样使用 | * + ? 等对单元内的项进行处理。
-
在完整的模式中定义子模式。当一个正则表达式成功与目标字符串匹配时,可以从目标串中抽出与圆括号中子模式匹配的部分。(书中后续有详解)
-
允许在同一正则表达式的后部引用前面的子表达式。通过字符
\
后加一位或多位数字实现的,数字代表了子表达式在正则表达式中的位置。例如: /([Jj]ava([Ss]cript)?)\sis\s(fun\w*)/ 中的 ([Ss]cript) 就可以用 \2 指代。
注: 对正则表达式字表达式的引用,不是针对子表达式模式的引用,而是指与那个模式相匹配的文本的引用,这样,引用可以用于实施一条约束,即一个字符串各个单独部分包含的是完全相同的字符,例如:
/['"][^'"]*['"]/ 匹配的是位于单引号或者双引号之间的0个或多个非引号字符,但是他不能让作用两端的引号匹配,可以改成这样 /(['"])[^'"]*\1/ ,但如果这样写 /(['"])[^\1]*\1/ 就是错误的,正则表达式不允许双引号内有单引号,反之亦然。
检索和替换强烈依赖此特性。
指定匹配位置
这些能匹配位置的字符也被称为正则表达式的锚。如下表:
字符 | 含义 |
---|---|
^ | 匹配字符串的开头,再多行检索中,匹配一行的开头 |
$ | 匹配字符串的结尾,在多行检索中,匹配一行的结尾 |
\b | 匹配单词的边界,简言之,就是\w和\W之间的位置,或位于字符\w和字符串的开头或者结尾之间的位置 |
\B | 匹配非单词边界的位置 |
(?=p) | 零宽正向先行断言,要求接下来的字符都与p匹配,但不包括匹配p的那些字符 |
(?!p) | 零宽负向先行断言,要求接下来的字符不与p匹配 |
几个例子:
匹配单词JavaScript,使用 /^JavaScript$/
匹配Java单词本身,需要使用 /\bJava\b/
/[Jj]ava([Ss]cript)?(?=\:)/ 能匹配JavaScript:The Definitive Guid,不能匹配Java is中的java。
/Java(?!Script)(A-Z\w*)/ 可以匹配JavaBeans但不能匹配JavaScript。
修饰符
字符 | 含义 |
---|---|
i | 不区分大小写 |
g | 全局匹配,简言之,找到所有匹配,而不是找一个就停止 |
m | 多行匹配,^匹配一行的开头和字符串的开头,$匹配行的结束和字符串的结束 |
用于模式匹配的String方法
search()方法
参数是一个正则表达式,返回第一个与之匹配的字串的起始位置,如果找不到匹配的字串,它将返回-1。比如:'JavaScript'.search(/script/i)
返回4。
同时,search方法不支持全局搜索,因为它会忽略正则表达式中的修饰符g。
replace()方法
执行检索和替换的功能。第一个参数是正则表达式,第二个参数是要进行替换的字符串。
如果指定了修饰符g,则会替换所有的匹配项,否则只替换第一个。
另外,上一篇文章中提到,正则表达式使用圆括号进行分组,同时这些括起来的内容从左到右是有索引编号的。如果在替换字符串中出现了$加数字,那么replace()将用与指定的字表达式相匹配的文本来替换这两个字符。比如:
var quote = /"([^"]*)"/g;
'abc"xxx"def'.replace(quote, '“$1”');//abc“xxx”def
此外,replace第二个参数还可以是函数。例如:
text.replace(/\b\w+\b/g, function(word) {
return word.substring(0,1).toUpperCase + word.substring(1);
})
match()方法
唯一参数就是正则表达式,返回一个由匹配项组成的数组。若设置了g则返回所有匹配项组成的数组。
另外,如果没有修饰符g,返回的数组中第一项是匹配的字符串,后面的项是正则表达式中圆括号括起来的项。
比如:
var url = /(\w+):\/\/([\w.]+)\/(\S*)/;
var text = 'Visit my blog http://www.example.com/~david';
//['http://www.example.com/~david', 'http', 'www.example.com', '~david']
split()方法
split的参数也支持正则表达式。
RegExp对象
- RegExp的五个属性
source:正则表达式的文本
global:是否有修饰符g
ignoreCase:是否有修饰符i
multiline:是否有修饰符multiline
lastIndex:如果有修饰符g,这个属性存储下一次开始检索的位置。
- 两个方法
exec()方法,与match类似,但总是返回一个结果,并返回lastIndex属性的信息。从而可以反复调用exec方法获得所有匹配。
test()方法,比exec更简单一些,如果包含匹配结果则返回true。