JavaScript 正则表达式 API

1. JavaScript 正则表达式API 共有 6 个,字符串实例 4 个,正则实例 2 个:

String#search
String#split
String#match
String#replace
RegExp#test
RegExp#exec

字符串对象正则方法
字符串对象共有 4 个方法,可以使用正则表达式:match()、replace()、search()和split()。
ES6 将这 4 个方法,在语言内部全部调用RegExp的实例方法,从而做到所有与正则相关的方法,全都定义在RegExp对象上。

String.prototype.match 调用 RegExp.prototype[Symbol.match]
String.prototype.replace 调用 RegExp.prototype[Symbol.replace]
String.prototype.search 调用 RegExp.prototype[Symbol.search]
String.prototype.split 调用 RegExp.prototype[Symbol.split]


2. RegExp 构造函数
在 ES5 中,RegExp构造函数的参数有两种情况。

第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。

var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;


第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。

var regex = new RegExp(/xyz/i);
// 等价于
var regex = /xyz/i;

但是,ES5 不允许此时使用第二个参数添加修饰符,否则会报错。ES6 可以:

var regex = new RegExp(/xyz/, 'i');
new RegExp(/abc/ig, 'i').flags


上面代码中,原有正则对象的修饰符是ig,它会被第二个参数i覆盖。


3. 正则表达式的四种操作

正则表达式首先是“匹配”,有了匹配这一基本操作后,才有其他的操作:验证、切分、提取、替换。

3.1 验证
判断一个字符串中是否有数字

var regex = /\d/;
var string = "abc123";
console.log( string.search(regex) );
console.log( regex.test(string) );
console.log( string.match(regex) );
// 输出
3
true
[ '1', index: 3, input: 'abc123', groups: undefined ]


3.2 切分
“切分”,就是把目标字符串,切成一段一段的。在 JavaScript 中使用的是 split。 比如,目标字符串是 "html,css,javascript",按逗号来切分:

var regex = /,/;
var string = "html,css,javascript";
console.log( string.split(regex) );
// => ["html", "css", "javascript"]


3.3 提取

虽然整体匹配上了,但有时需要提取部分匹配的数据。
此时正则通常要使用分组引用(分组捕获)功能,还需要配合使用相关 API。 这里,还是以日期为例,提取出年月日。注意下面正则中的括号:

//使用match:
varregex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
varstring = "2017-06-26";
console.log(string.match(regex));
//=>["2017-06-26","2017","06","26",index:0,input:"2017-06-26"]

//使用exec:
varregex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
varstring = "2017-06-26";
console.log(regex.exec(string));
//=>["2017-06-26","2017","06","26",index:0,input:"2017-06-26"]

//使用test:
varregex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
varstring = "2017-06-26";
regex.test(string);
console.log(RegExp.$1, RegExp.$2, RegExp.$3);
//=>"2017""06""26"

//使用search:
varregex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
varstring = "2017-06-26";
string.search(regex);
console.log(RegExp.$1, RegExp.$2, RegExp.$3);
//=>"2017""06""26"

//使用replace:
varregex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
varstring = "2017-06-26";
vardate = [];
string.replace(regex, function (match, year, month, day) {
    date.push(year, month, day);
});
console.log(date);
 //=>["2017","06","26"]


其中,最常用的是 match。


3.4 替换
找,往往不是目的,通常下一步是为了替换。在 JavaScript 中,使用 replace 进行替换。 比如把日期格式,从 yyyy-mm-dd 替换成 yyyy/mm/dd:

var string = "2017-06-26";
string.replace(/-/g, "/") 
console.log( today );
// => 2017/06/26


这里只是简单地应用了一下 replace。但,replace 方法很是强大的,是需要重点掌握的。

 

4. 函数详解

4.1 search 函数

var string = "2017.06.27"; 
console.log( string.search(".") ); 
// => 0
//需要修改成下列形式之一 
console.log( string.search("\\.") ); 
console.log( string.search(/\./) ); 
// => 4
// => 4



4.2 match函数
match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。

语法
stringObject.match(searchvalue)
stringObject.match(regexp)
searchvalue    必需。规定要检索的字符串值。
regexp    必需。规定要匹配的模式的 RegExp 对象。如果该参数不是 RegExp 对象,则需要首先把它传递给 RegExp 构造函数,将其转换为 RegExp 对象。

返回值
match 返回结果的格式,与正则对象是否有修饰符 g 有关。

var string = "2017.06.27";
var regex1 = /\b(\d+)\b/;
var regex2 = /\b(\d+)\b/g;
console.log( string.match(regex1) );
console.log( string.match(regex2) );
// => ["2017", "2017", index: 0, input: "2017.06.27"]
// => ["2017", "06", "27"]

如果没有标志 g,那么 match() 方法就只执行一次匹配。
如果没有找到任何匹配的文本, match() 将返回 null。
如果匹配到,会返回一个数组。该数组的第 0 个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本。index 是匹配文本的起始字符的位置,input 是被搜索字符串。

4.3 exec函数
当正则没有 g 时,使用 match 返回的信息比较多。但是有 g 后,就没有关键的信息 index 了。
而 exec 方法就能解决这个问题,它能接着上一次匹配后继续匹配:

var string = "2017.06.27";
var regex2 = /\b(\d+)\b/g;
console.log( regex2.exec(string) );
console.log( regex2.lastIndex);
console.log( regex2.exec(string) );
console.log( regex2.lastIndex);
console.log( regex2.exec(string) );
console.log( regex2.lastIndex);
console.log( regex2.exec(string) );
console.log( regex2.lastIndex);
// => ["2017", "2017", index: 0, input: "2017.06.27"]
// => 4
// => ["06", "06", index: 5, input: "2017.06.27"]
// => 7
// => ["27", "27", index: 8, input: "2017.06.27"]
// => 10
// => null
// => 0


其中正则实例 lastIndex 属性,表示下一次匹配开始的位置。
比如第一次匹配了 "2017",开始下标是 0,共 4 个字符,因此这次匹配结束的位置是 3,下一次开始匹配
的位置是 4。
从上述代码看出,在使用 exec 时,经常需要配合使用 while 循环:

var string = "2017.06.27";
var regex2 = /\b(\d+)\b/g;
var result;
while ( result = regex2.exec(string) ) {
    console.log( result, regex2.lastIndex );
}
// => ["2017", "2017", index: 0, input: "2017.06.27"] 4
// => ["06", "06", index: 5, input: "2017.06.27"] 7
// => ["27", "27", index: 8, input: "2017.06.27"] 10


4.4 test函数

上面提到了正则实例的 lastIndex 属性,表示尝试匹配时,从字符串的 lastIndex 位开始去匹配。
字符串的四个方法,每次匹配时,都是从 0 开始的,即 lastIndex 属性始终不变。

而正则实例的两个方法 exec、test,当正则是全局匹配时,每一次匹配完成后,都会修改 lastIndex。下面 让我们以 test 为例,看看你是否会迷糊:

var regex = /a/g;
console.log( regex.test("a"), regex.lastIndex );
console.log( regex.test("aba"), regex.lastIndex );
console.log( regex.test("ababc"), regex.lastIndex );
// => true 1
// => true 3
// => false 0

注意上面代码中的第三次调用 test,因为这一次尝试匹配,开始从下标 lastIndex,即 3 位置处开始查 找,自然就找不到了。
如果没有 g,自然都是从字符串第 0 个字符处开始尝试匹配:

var regex = /a/;
console.log( regex.test("a"), regex.lastIndex );
console.log( regex.test("aba"), regex.lastIndex );
console.log( regex.test("ababc"), regex.lastIndex );
// => true 0
// => true 0
// => true 0

test 整体匹配时需要使用 ^ 和 $,如果,要整体匹配,正则前后需要添加开头和结尾:

console.log( /123/.test("a123b") );
// => true
console.log( /^123$/.test("a123b") );
// => false
console.log( /^123$/.test("123") );
// => true


 

参考:《JavaScript正则表达式迷你书》 《ES6 标准入门》

修改时间 2019-06-12

真诚赞赏,手留余香
赞赏
随机推荐
js解析json中的一个问题
Nginx location 匹配顺序
CentOS 安全
MySQL中UNION和UNION ALL的使用
Fatal error:Call-time pass-by-reference has been removed
npm warn package.json @1.0.0 no repository field
移动端UI设计规范「小白干货」
CentOS 7 服务管理命令 systemctl
V8引擎、 libuv 和 N-API
MySQL AUTO_INCREMENT 自动增长的一些知识