JS对象类型-RegExp
本篇文章主要介绍RegExp对象以及RegExp的实例的属性和方法,如果对于正则的基础语法还不是很清楚,可以参考下RegExp基础语法这篇文章
实例属性
RegExp实例都包含下面5个属性
global: 布尔值,表示是否设置了g标志
ignoreCase: 布尔值,表示是否设置了i标志
multiline:布尔值,表示是否设置了m标志
lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从0开始
source:正则表达式的字符串表示(按照字面量形式而非传入构造函数中的字符串模式返回)
var p1 = /[bc]at/i;
console.log(p1.global);//false
console.log(p1.ignoreCase);//true
console.log(p1.multiline);//false
console.log(p1.lastIndex);//0
console.log(p1.source);//'[bc]at'
如果设置了RegExp的全局模式'g',使用exec()或test()函数时,正则表达式的匹配就会从lastIndex的位置开始,并且在每次匹配成功之后重新设定lastIndex。这样,就可以在字符串中重复迭代,依次寻找各个匹配结果。但是,如果需要对不同字符串调用同一个RegExp的exec()或test()方法,这个变量可能会带来意料之外的匹配结果,所以在更换字符串时,要显式地将RegExp的lastIndex置为0
var p1 = /\w/g;
var s1 = 'ab';
var s2 = 'ba';
// 默认值
console.log(p1.lastIndex); // 0
p1.exec(s1);
console.log(p1.lastIndex); // 1
// s2从位置1开始匹配
p1.exec(s2);
console.log(p1.lastIndex); // 2
构造函数属性
RegExp构造函数属性会基于所执行的最近一次正则表达式操作而变化。有两种方式访问它们,即长属性名和短属性名,短属性名大都不是有效的ECMAScript标识符,所以必须通过方括号语法来访问它们
长属性名 短属性名 说明
input $_ 最近一次要匹配的字符串
lastMatch $& 最近一次的匹配项
lastParen $+ 最近一次匹配的捕获组
leftContext $` input字符串中lastMatch之前的文本
rightContext $' input字符串中lastMatch之后的文本
multiline $* 布尔值,表示是否所有表达式都使用多行模式
var text = 'this has been a short summer';
var pattern = /(.)hort/g;
if(pattern.test(text)){
console.log(RegExp.input);//'this has been a short summer'
console.log(RegExp.leftContext);//'this has been a '
console.log(RegExp.rightContext);//' summer'
console.log(RegExp.lastMatch);//'short'
console.log(RegExp.lastParen);//'s'
console.log(RegExp.multiline);//false
console.log(RegExp['$_']);//'this has been a short summer'
console.log(RegExp['$`']);//'this has been a '
console.log(RegExp["$'"]);//' summer'
console.log(RegExp['$&']);//'short'
console.log(RegExp['$+']);//'s'
console.log(RegExp['$*']);//false
}
JavaScript有9个用于存储捕获组的构造函数属性,RegExp.$1、RegExp.$2、RegExp.$3……到RegExp.$9分别用于存储第一、第二……第九个匹配的捕获组。在调用exec()或test()方法时,这些属性会被自动填充
比如,要匹配诸如2018-08-12这样的日期字符串
/(\d{4})-(\d{2})-(\d{2})/.test('2018-08-12');
console.log(RegExp.$1);//'2018'
console.log(RegExp.$2);//'08'
console.log(RegExp.$3);//'12'
console.log(RegExp.$4);//''
// 理论上,应该保存整个表达式匹配文本的RegExp.$0并不存在,值为undefined
console.log(RegExp.$0);//undefined
实例方法
实例方法分为两类:一类是是继承而来的,包括toString()、toLocalString()、valueOf();一类是非继承的,包括test()和exec()
继承方法
RegExp对象继承了Object对象的通用方法toString()、toLocaleString()、valueOf()这三个方法
toString():toString()方法返回正则表达式的字面量
toLocaleString():toLocaleString()方法返回正则表达式的字面量
valueOf():valueOf()方法返回返回正则表达式对象本身
var pattern = new RegExp('[bc]at','gi');
console.log(pattern.toString()); // '/[bc]at/gi'
console.log(pattern.toLocaleString()); // '/[bc]at/gi'
console.log(pattern.valueOf()); // /[bc]at/gi
var pattern = /[bc]at/gi;
console.log(pattern.toString()); // '/[bc]at/gi'
console.log(pattern.toLocaleString()); // '[bc]at/gi'
console.log(pattern.valueOf()); // /[bc]at/gi
注意: 不论以哪种方式创建正则表达式,这三个方法都只返回其字面量形式
exec()
exec()方法专门为捕获组而设计,接受一个参数,表示要应用模式的字符串,返回包含匹配项信息的数组,在没有匹配项的情况下返回null
匹配项数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含第一项)
返回的数组包含两个额外的属性:index和input。index表示匹配项在字符串的位置,input表示应用正则表达式的字符串
console.log(/(\d{4})-(\d{2})-(\d{2})/.exec('date 2018-08-12 10:30'));
对于exec()方法,在不设置全局标志的情况下,在同一个字符串上多次调用exec(),将始终返回第一个匹配项的信息;而在设置全局标志的情况下,每次调用exec()都会在字符串中继续查找新匹配项。
无全局标志示例
var text = 'cat,bat,sat,fat';
var pattern = /.at/;
var m1 = pattern.exec(text);
console.log(m1);
var m2 = pattern.exec(text);
console.log(m2);
有全局标志示例
var text = 'cat,bat,sat,fat';
var pattern = /.at/g;
var m1 = pattern.exec(text);
console.log(m1);
var m2 = pattern.exec(text);
console.log(m2);
扩展: 用exec()方法找出所有匹配项的位置和值
var str = 'a1b2c3d4';
var p = /[a-z]/g;
var i = [], v = [], ret;
while((ret = p.exec(str)) != null) {
i.push(ret.index);
v.push(ret[0]);
}
console.log(i, v); // [0, 2, 4, 6] ["a", "b", "c", "d"]
test()
test()方法用来测试正则表达式能否在字符串中找到匹配文本,接收一个字符串参数,匹配时返回true,否则返回false
/\d/.test('1'); // true
/\d/.test('a'); // false
同样地,在调用test()方法时,会造成RegExp对象的lastIndex属性的变化。如果指定了全局模式,每次执行test()方法时,都会从字符串中的lastIndex偏移值开始尝试匹配,所以用同一个RegExp多次验证不同字符串,必须在每次调用之后,将lastIndex值置为0
var pattern = /^\d{4}-\d{2}-\d{2}$/g;
console.log(pattern.test('2018-08-12'));//true
console.log(pattern.test('2018-08-12'));//false
//正确的做法应该是在验证不同字符串前,先将lastIndex重置为0
var pattern = /^\d{4}-\d{2}-\d{2}$/g;
console.log(pattern.test('2018-08-12'));//true
pattern.lastIndex = 0;
console.log(pattern.test('2018-08-12'));//true