一、概述
正则表达式(regular expression)是一种表达文本模式(即字符串结构)的方法,有点像字符串的模板,常常用来按照“给定模式”匹配文本。比如,正则表达式给出一个 Email 地址的模式,然后用它来确定一个字符串是否为 Email 地址。JavaScript 的正则表达式体系是参照 Perl 5 建立的。
新建正则表达式有两种方法。一种是使用字面量,以斜杠表示开始和结束。
var regex = /xyz/;
另一种是使用RegExp构造函数。
var regex = new RegExp('xyz');
上面两种写法是等价的,都新建了一个内容为xyz的正则表达式对象。它们的主要区别是,第一种方法在引擎编译代码时,就会新建正则表达式,第二种方法在运行时新建正则表达式,所以前者的效率较高。而且,前者比较便利和直观,所以实际应用中,基本上都采用字面量定义正则表达式。<br />RegExp构造函数还可以接受第二个参数,表示修饰符(详细解释见下文)。
var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;
上面代码中,正则表达式/xyz/有一个修饰符i。
二、实例属性
2.1 修饰符相关
一类是修饰符相关,用于了解设置了什么修饰符。
- RegExp.prototype.ignoreCase:返回一个布尔值,表示是否设置了i修饰符。
- RegExp.prototype.global:返回一个布尔值,表示是否设置了g修饰符。
- RegExp.prototype.multiline:返回一个布尔值,表示是否设置了m修饰符。
- RegExp.prototype.flags:返回一个字符串,包含了已经设置的所有修饰符,按字母排序。
上面四个属性都是只读的。
var r = /abc/igm;
r.ignoreCase // true
r.global // true
r.multiline // true
r.flags // 'gim'
2.2 修饰符无关的属性
另一类是与修饰符无关的属性,主要是下面两个。
- RegExp.prototype.lastIndex:返回一个整数,表示下一次开始搜索的位置。该属性可读写,但是只在进行连续搜索时有意义,详细介绍请看后文。
- RegExp.prototype.source:返回正则表达式的字符串形式(不包括反斜杠),该属性只读。 ```javascript var r = /abc/igm;
r.lastIndex // 0 r.source // “abc”
<a name="tBWuY"></a>
# 三、实例方法
<a name="aRYfH"></a>
## 3.1 RegExp.prototype.test()
正则实例对象的test方法返回一个布尔值,表示当前模式是否能匹配参数字符串。
```javascript
/cat/.test('cats and dogs') // true
上面代码验证参数字符串之中是否包含cat,结果返回true。
如果正则表达式带有g修饰符,则每一次test方法都从上一次结束的位置开始向后匹配。
var r = /x/g;
var s = '_x_x';
r.lastIndex // 0
r.test(s) // true
r.lastIndex // 2
r.test(s) // true
r.lastIndex // 4
r.test(s) // false
上面代码的正则表达式使用了g修饰符,表示是全局搜索,会有多个结果。接着,三次使用test方法,每一次开始搜索的位置都是上一次匹配的后一个位置。
带有g修饰符时,可以通过正则对象的lastIndex属性指定开始搜索的位置。
var r = /x/g;
var s = '_x_x';
r.lastIndex = 4;
r.test(s) // false
r.lastIndex // 0
r.test(s)
上面代码指定从字符串的第五个位置开始搜索,这个位置为空,所以返回false。同时,lastIndex属性重置为0,所以第二次执行r.test(s)会返回true。
注意,带有g修饰符时,正则表达式内部会记住上一次的lastIndex属性,这时不应该更换所要匹配的字符串,否则会有一些难以察觉的错误。
var r = /bb/g;
r.test('bb') // true
r.test('-bb-') // false
上面代码中,由于正则表达式r是从上一次的lastIndex位置开始匹配,导致第二次执行test方法时出现预期以外的结果。
lastIndex属性只对同一个正则表达式有效,所以下面这样写是错误的, 会导致死循环。
//错误写法,死循环
var count = 0;
while (/a/g.test('babaa')) count++;
//正确写法
var reg = /a/g;
var count = 0;
while (reg.test('babaa')) count++;
上面代码会导致无限循环,因为while循环的每次匹配条件都是一个新的正则表达式,导致lastIndex属性总是等于0。
如果正则模式是一个空字符串,则匹配所有字符串。
new RegExp('').test('abc')
// true
3.2 RegExp.prototype.exec()
正则实例对象的exec()方法,用来返回匹配结果。如果发现匹配,就返回一个数组,成员是匹配成功的子字符串,否则返回null。
var s = '_x_x';
var r1 = /x/;
var r2 = /y/;
r1.exec(s) // ["x"]
r2.exec(s) // null
上面代码中,正则对象r1匹配成功,返回一个数组,成员是匹配结果;正则对象r2匹配失败,返回null。
如果正则表示式包含圆括号(即含有“组匹配”),则返回的数组会包括多个成员。第一个成员是整个匹配成功的结果,后面的成员就是圆括号对应的匹配成功的组。也就是说,第二个成员对应第一个括号,第三个成员对应第二个括号,以此类推。整个数组的length属性等于组匹配的数量再加1。
var s = '_x_x';
var r = /_(x)/;
r.exec(s) // ["_x", "x"]
上面代码的exec()方法,返回一个数组。第一个成员是整个匹配的结果,第二个成员是圆括号匹配的结果。
exec()方法的返回数组还包含以下两个属性:
- input:整个原字符串。
- index:模式匹配成功的开始位置(从0开始计数)。 ```javascript var r = /a(b+)a/; var arr = r.exec(‘abbba_aba‘);
arr // [“abbba”, “bbb”]
arr.index // 1 arr.input // “abbba_aba“
上面代码中的index属性等于1,是因为从原字符串的第二个位置开始匹配成功。
如果正则表达式加上g修饰符,则可以使用多次exec()方法,下一次搜索的位置从上一次匹配成功结束的位置开始。
```javascript
var reg = /a/g;
var str = 'abc_abc_abc'
var r1 = reg.exec(str);
r1 // ["a"]
r1.index // 0
reg.lastIndex // 1
var r2 = reg.exec(str);
r2 // ["a"]
r2.index // 4
reg.lastIndex // 5
var r3 = reg.exec(str);
r3 // ["a"]
r3.index // 8
reg.lastIndex // 9
var r4 = reg.exec(str);
r4 // null
reg.lastIndex // 0
上面代码连续用了四次exec()方法,前三次都是从上一次匹配结束的位置向后匹配。当第三次匹配结束以后,整个字符串已经到达尾部,匹配结果返回null,正则实例对象的lastIndex属性也重置为0,意味着第四次匹配将从头开始。
利用g修饰符允许多次匹配的特点,可以用一个循环完成全部匹配。
var reg = /a/g;
var str = 'abc_abc_abc'
while(true) {
var match = reg.exec(str);
if (!match) break;
console.log('#' + match.index + ':' + match[0]);
}
// #0:a
// #4:a
// #8:a
上面代码中,只要exec()方法不返回null,就会一直循环下去,每次输出匹配的位置和匹配的文本。
正则实例对象的lastIndex属性不仅可读,还可写。设置了g修饰符的时候,只要手动设置了lastIndex的值,就会从指定位置开始匹配。
四、字符串的实例方法
字符串的实例方法之中,有4种与正则表达式有关。