正则表达式(regular expression)是一个描述字符模式的对象。在 JavaScript 中 String 和 RegExp 都定义了相关方法对文本进行模式匹配、检索和替换
正则表达式的定义
JavaScript 中的正则表达式用 RegExp 对象表示,可以使用 RegExp() 构造函数来创建 RegExp 对象,不过也可以通过两个双斜杠「/reg/」以正则直接量的形式创建
var pattern = /s$/; // 通过直接量创建
var pattern = new RegExp('s$'); // 通过构造函数创建
直接量字符
JavaScript 正则表达式语法也支持非字母的字符匹配,这些字符需要通过反斜线(\)作为前缀进行转义
表10-1
字符 | 匹配 |
---|---|
字母和数字 | 自身 |
\0 | NUL 字符(\u0000) |
\t | 制表符(\u0009) |
\n | 换行符(\u000A) |
\v | 垂直制表符(\u000B) |
\f | 换页符(\u000C) |
\r | 回车符(\u000D) |
\xnn | 由十六进制数 nn 指定的拉丁字符 |
\uxxxx | 由十六进制数 xxxx 指定的 unicode 字符 |
\cX | 控制字符 ^x |
正则表达式中,许多标点符号也具有特殊含义,它们是:
^ $ . * + ? = ! : | \ / ( ) { }
字符类
将直接量字符单独放进方括号内组成了字符类(charactor class)
表10-2
字符 | 匹配 |
---|---|
[…] | 方括号内的任意字符 |
[^…] | 不在方括号内的任意字符 |
. | 除换行符和其它 Unicode 行终止符之外的任意字符 |
\w | 任何 ASCII 字符组成的单词,等价于 [a-zA-Z0-9] |
\W | 任何不是 ASCII 字符组成的单词,等价于 [^a-zA-Z0-9] |
\s | 任何 Unicode 空白符 |
\S | 任何非 Unicode 空白符 |
\d | 任何 ASCII 数字,等价于 [0-9] |
\D | 任何非 ASCII 数字,等价于 [^0-9] |
[\b] | 退格直接量 |
重复
表10-3
字符 | 含义 |
---|---|
{n, m} | 匹配前一项至少 n 次,但不能超过 m 次 |
{n,} | 匹配前一项 n 次或者更多次 |
{n} | 匹配前一项 n 次 |
? | 匹配前一项 0 次或者 1 次,也就是说前一项是可选的,等价于 {0,1} |
+ | 匹配前一项 1 次或者多次,等价于 {1,} |
* | 匹配前一项 0 次或者多次,等价于{0,} |
举例说明:
/\d{2,4}/ // 匹配 2 ~ 4 个数字
/\w{3}\d?/ // 匹配三个单词和一个可选的数字
/\s+java\s+/ // 匹配前后带有一个或者多个空白字符串 "java"
/[^(]*/ // 匹配一个或多个非左括号字符
非贪婪的重复
表10-3 中列出一匹配重复字符是尽可能多地匹配,而且允许后续的正则表达式继续匹配。因此,我们称之为「贪婪的」匹配。我们同样可以使用正则表达式进行非贪婪匹配。只需在特匹配的字符后跟随一个问题即可:「??」、「+?」、「*?」或「{1,5}?」
选择、分级和引用
表10-4
字符 | 含义 |
---|---|
| | 选择,匹配的是该符号左边的子表达式或者右边的子表达式 |
(…) | 组合,将几个项组合为一个单元,这个单元可通过「*」、「+」、「?」和「|」等符号 加以修饰,而且可以记住和这个组合相匹配的字符串 以供此后的引用使用 |
(?:…) | 只组合,把项组合到一个单元,但不记忆与该组想匹配的字符 |
\n | 和第 n 个分级第一次匹配的字符相匹配,组是圆括号中的子表达式 (也有可能是嵌套的),组索引是从左到右的左括号数, 「(?:」形式的分组不编码 |
指定匹配位置
表10-5
字符 | 含义 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的结尾 |
\b | 匹配一个单词的边界 |
\B | 匹配非单词边界的位置 |
(?=p) | 零宽正向先行断言,要求接下来的字符都与 p 匹配,但不能包括匹配 p 的那些字符 |
(?!p) | 零宽负向先行断言,要求接下来的字符都不与 p 匹配 |
标识
/reg/flag
标识是放在斜扛右边的,通常有 i, g, m 三种
- i 执行不区分大小写的匹配
- g 执行一个全局匹配,即 找到所有的匹配,而不是找到第一个就停止
- m 多行匹配模式
用于模式匹配的 string 方法
String 支持 4 种使用正则表达式的方法
String.prototype.search()
search() 方法返回第一个与之匹配的子串起始位置,如果找不到匹配的子串,它将返回 -1
"JavaScript".search(/script/i); // => 4
如果 search() 参数不是正则表达式,则首先会 通过 RegExp 构造函数将它转换成正则表达式,search() 方法不支持全局检索,因为它 忽略 正则表达式参数中的标识 g
String.prototype.replace()
str.replace(regexp|substr, newSubStr|function)
replace() 方法用以执行检索与替换操作,正则表达式如果带标识 g,则会替换所有匹配子串
// 将所有不区分大小写的 javascript 都替换成 JavaScript
text.replace(/javascript/gi);
// 用中文引号替换英文应该引号,同时要保持引号之间的内容(存储在 $1 中)没有被修改
var quote = /"([^"]*)"/g;
text.replace(quote, '“$1”')
String.prototype.match()
match() 方法返回一个由匹配结果组成的数组,如果没有标识全局搜索,match() 只检索第一个匹配
"1 plus 2 equals 3".match(/\d+/g); // => ["1", "2", "3"]
RegExp 对象
RegExp(pattern [, flags])
RegExp 构造函数一般用在动态创建正则表达式的时候,这种情况往往没办法通过写死在代码中的正则直接量来实现,比如检索字符串是用户输出的
RegExp 的属性
每个 RegExp 对象都包含 5 个属性:
- source 只读字符串,包含正则表达式的文本
- global 只读布尔值,说明正则表达式是否带全局标识 g
- ignoreCase 也是一个只读布尔值,说明正则表达式是否带标识 i
- multiline 也是一个只读布尔值,说明正则表达式是否带标识 m
- lastIndex 它是一个可读/写的整数。如果匹配模式带有 g 标识,这个属性存储在整个字符串中下一次检索的开始位置
RegExp 的方法
exec()
exec() 对一个指定的字符串执行一个正则表达式,如果没有找到任何匹配,它就返回 null,但如果它找到一个匹配,将返回一个数组
var pattern = /Java/g;
var text = "JavaScript is more fun than Java!";
var result;
while((result = pattern.exec(text)) != null) {
console.log("Matched '%s' at position '%s'; next search begins at %s",
result[0],
result.index,
pattern.lastIndex);
}
// Matched 'Java' at position '0'; next search begins at 4
// Matched 'Java' at position '28'; next search begins at 32
test()
test() 对方法转入字符串进行检测,匹配到结果返回 true,否则返回 false
var pattern = /java/i;
pattern.test('JavaScript'); // => true