正则分组详解

1,357 阅读3分钟

这是我参与 8 月更文挑战的第 16 天,活动详情查看: 8月更文挑战

分组捕获,使用()进行数据分组,编号0代表整个匹配项,选择的分组从1号开始

{n}匹配最后字符重复了3次,并不能匹配整个单词重复三次的情况

var reg = /lian{3}/g;
var text = 'lianlianliannn';
var result = text.replace(reg,'x');
console.log(result);//lianlianx

如果我们要匹配lian连续出现3次的情况呢,正则表达式的分组'()'就帮我们解决了这个问题:

var reg = /(lian){3}/g;
var text = 'lianlianliannn';
var result = text.replace(reg,'x');
console.log(result);//xnn

反向引用

表达式在匹配时,表达式引擎会将小括号 "( )" 包含的表达式所匹配到的字符串记录(分组捕获)下来。在获取匹配结果的时候,小括号包含的表达式所匹配到的字符串可以单独获取。

在js中正则匹配成功的字符串可以用1表示第一次匹配成功,1表示第一次匹配成功,3表示第三次匹配成功的字符

var reg = /(\d{4})-(\d{2})-(\d{2})/g;
var text = '2015-12-25'
var result = text.replace(reg,'$2/$3/$1');
console.log(result);//12/25/2015

忽略分组

默认是根据'()'全部捕获记录为1 1~99的,不希望捕获某些分组,只需要在分组内加上?:就可以了。

var reg = /(?:Lian)(\d{4})-(\d{2})-(\d{2})/g;
var text = 'Lian2016-12-05'
var result = text.replace(reg,'$2/$3/$1');
console.log(result);//12/05/2016

前瞻后顾断言

名称正则含义
正向前瞻exp(?=assert)后边是什么,我们匹配符合了exp部分的表达式,然后还不算完,必须也匹配断言部分('()'内部,'='后面的正则),才算成功
负向前瞻exp(?!assert)后边不是什么,我们匹配符合了exp部分的表达式,然后还不算完,必须也匹配断言部分('()'内部,'!'后面的正则),才算成功
正向后顾(?<=assert)exp后行断言,就是前面是什么
负向后顾(?<!assert)exp负向后行断言,就是前面不是什么

断言里面内容只是作为匹配的条件之一,也是必须的条件,但是匹配的本质只匹配"()"前面的正则

var reg = /\w(?=\d)/g;
var text = 'a2*3';
var result = text.replace(reg,'X');
console.log(result);//X2*3

题目

lastIndex

正则每次匹配并不是从头开始的,而是从上次的结果往后找,看看后面还有没有,有的话继续匹配,当然这必须是在'g'全局匹配的基础上,不然每次匹配都是从头开始的。

var reg1 = /\w/;
var reg2 = /\w/g;

console.log(reg1.test('a'));//true
console.log(reg1.test('a'));//true
console.log(reg1.test('a'));//true
//... 不管执行多少次都是true

//第一次匹配到'a'字符,匹配结果的最后一位字符也是'a','a'字符的下一个位置的index就是1了。类似的第二次匹配'b',匹配结果的最后一位字符也是'b','b'字符的下一个位置的index就是2
while(reg2.test('ab')){ 
    console.log(reg2.lastIndex); // 1 2 
}

console.log(reg2.test('ab'));//true
console.log(reg2.test('ab'));//true
console.log(reg2.test('ab'));//false
console.log(reg2.test('ab'));//true
console.log(reg2.test('ab'));//true
console.log(reg2.test('ab'));//false
//... 循环true true false

group

//match返回一个数组,下标0为匹配文本,1、2、3...匹配的为原子组
'pig'.match(/p((i)(g))/)  // ["pig","ig","i","g"]

const str = 'name=pig'
str.match(/(?<key>.+)=(?<value>.+)/) 
// 结果的groups 
{
    key: "name"
    value: "pig"
}

转义\

const reg = new RegExp('\d') //这里我们传入的是字符串'\d' 那他匹配的是什么?
reg.test(1)  // false
reg.test('\d') // true

在字符串中 \ 代表的是转义
'\d' === 'd'  // true   d经过 \的转义还是d,所以我们需要这样写
const reg2 = new RegExp('\\d')
reg.test(1) // true
//其实通过在控制台直接打印 reg我们也可以看到 得到的是/d/ 而不是/\d/
//所以当在对象创建正则中使用\d、\w等需要多加一个\。

分离标签内容

const str = `<span>pig1</span><span>pig2</span>dog<span>pig3</span>`
str.match(/<span>.+<\/span>/g)  
// ["<span>pig1</span><span>pig2</span>dog<span>pig3</span>"]  
因为正则时贪婪的所以它会尽可能的多匹配 就变成了开头的span 一直匹配到字符串结尾的span,所以我们要禁止贪婪
str.match(/<span>.+?<\/span>/g)   
// ["<span>pig1</span>", "<span>pig2</span>", "<span>pig3</span>"] 尽可能的少匹配

日期替换

yyyy-mm-dd 格式,替换成 mm/dd/yyyy

//replace 第二个参数里用`$1、$2、$3`指代相应的分组
var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
var result = string.replace(regex, "$2/$3/$1");
console.log(result); // "06/12/2017"

var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
var result = string.replace(regex, function() {
	return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1;
});
console.log(result); // "06/12/2017"

var regex = /(\d{4})-(\d{2})-(\d{2})/;
var string = "2017-06-12";
var result = string.replace(regex, function(match, year, month, day) {
	return month + "/" + day + "/" + year;
});
console.log(result); // "06/12/2017"