括号?谁不会,不就是括起来的是一个子表达式吗?no no no
这篇文章的问题:
- 什么是分组?
- 什么是分组的引用?
- 什么是反向引用?
- 括号嵌套了怎么办?
- \10 表示的什么呢?
- 分组不存在会怎么样呢?
- 分组后面有量词会怎么样呢?
- 什么是非捕获括号?
什么是分组?
其实就是括号的作用,它提供了分组,以便我们引用它。
例如/a+/
匹配连续出现的"a"
,而要匹配连续出现的"ab"
时,就需要使用括号把他们括起来/(ab)+/
.
其中括号是提供分组功能,让量词+
作用于"ab"
这个整体。
var regex = /(ab)+/g
var string = "ababa abbb ababab";
// => ["abab", "ab", "ababab"]
什么是分支结构?
分支结构就是我们之前学习的那个,使用管道符|
来间隔多个子表达式。
(p1|p2)
它同样是我们括号的作用。
var regex = /^I love (JavaScript|Regular Expression)$/;
console.log( regex.test("I love JavaScript") );
console.log( regex.test("I love Regular Expression") );
// => true
// => true
什么是分组的引用呢?
这是括号一个非常重要的作用,有了它我们就可以进行数据提取,以及更强大的替换操作。
而要使用它,就必须配合使用实现环境的API
。
以日期为例,假设格式为yyyy-mm-dd
。我们可以先写一个简单的正则。
var regex = /\d{4}-\d{2}-\d{2}/
可视化是这样的。

而如果添加了括号:
var regex = /(\d{4})-(\d{2})-(\d{2})/
可视化则是:

可以看到它们每一个被
group
所包裹。
正则引擎就是这么干的,在匹配过程中,给每一个分组都开辟一个空间,用来存储每一个分组匹配到的数据。
既然数据已经存储到空间里,那当然我们就可以引用它们。
提取数据
如果提取出年,月,日,可以这么做。
var regex = /(\d{4})-(\d{2})-(\d{2})/
var string = "2017-06-12";
console.log(string.match(regex))
返回的数据时这样:
[
'2017-06-12',
'2017',
'06',
'12',
index: 0,
input: '2017-06-12',
groups: undefined
]
同样也可以使用正在实例对象的exec
方法。
var regex = /(\d{4})-(\d{2})-(\d{2})/
var string = "2017-06-12";
console.log(regex.exec(string))
同时也可以使用构造函数的全局树形$1
和$9
来获取。
var regex = /(\d{4})-(\d{2})-(\d{2})/
var string = "2017-06-12";
//正则操作就可以。同样也可以使用:
//regex.exec(string);
//string.match(regex);
regex.test(string);
console.log(RegExp.$1)
console.log(RegExp.$2)
console.log(RegExp.$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);
其中后面的$2
,$3
,$1
其实就是分组的引用。
反向引用
除了使用相应 API
来引用分组,也可以在正则本身里引用分组。但只能引用之前出现的分组,即反向引用。
比如要写一个正则来支持匹配下面三种格式:
2016-06-12
2016/06/12
2016.06.12
我们可以写出这样的正则:
var regex = /\d{4}(-|\/|\.)\d{2}-|\/|\.)\d{2}/
var string1 = "2017-06-12";
var string2 = "2017/06/12";
var string3 = "2017.06.12";
var string4 = "2016-06/12";
console.log( regex.test(string1) ); // true
console.log( regex.test(string2) ); // true
console.log( regex.test(string3) ); // true
console.log( regex.test(string4) ); // true
其中/
和.
需要转义,它的问题就是:虽然满足了以上的要求,但是同样匹配到了2016-06/12
这样的数据。
如果我们想要前后一致,就需要使用反向引用了。
var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/
可视化是这样:

可以看到我们和之前的区别,\1
它就是之前(-|\/|\.)
的引用。无论它匹配到的是什么,那么这里就是什么。
既然\1
是第一个分组,那么\2
和\3
就是指第二个和第三个分组。
括号嵌套怎么办?
以左括号(开括号)为准。
如:
var regex = /^((\d)(\d(\d)))\1\2\3\4$/;
var string = "1231231233";
console.log( regex.test(string) ); // true
console.log( RegExp.$1 ); // 123
console.log( RegExp.$2 ); // 1
console.log( RegExp.$3 ); // 23
console.log( RegExp.$4 ); // 3
它的可视化是:

\10 表示的什么呢?
表示的是第10个分组。
引用不存在怎么办?
因为反向引用,是引用前面的分组,但是我们正在里引用了不存在的分组的时候,也不会报错,就是会匹配反向引用的字符本身。
例如\2
就是匹配\2
了,
分组后面有量词会怎样?
分组后面有量词的话,分组最终捕获到的数据时最后一次的匹配
var regex = /(\d)+/;
var string = "12345";
console.log( string.match(regex) );
// => ["12345", "5", index: 0, input: "12345"]
可以看到我们的分组(\d)
捕获的数据时5.
同样反向引用,我们也还可以这样玩。
var regex = /(\d)+ \1/;
console.log( regex.test("12345 1") );
// => false
console.log( regex.test("12345 5") );
// => true
非捕获括号
之前稳重出现的括号,都会捕获它们匹配到的数据,以便后续引用,因此也称它们为捕获型分组和捕获型分支。
如果只想要括号最原始的功能,但不会引用它,既不在api
里引用,也不在正则里引用。此时可以使用非捕获括号(?:p)
和(?:p1|p2|p3)
var regex = /(?:ab)+/g;
var string = "ababa abbb ababab";
console.log( string.match(regex) );
// => ["abab", "ab", "ababab"]
同理,第二个例子也可以是这样:
var regex = /^I love (?:JavaScript|Regular Expression)$/;
console.log( regex.test("I love JavaScript") );
console.log( regex.test("I love Regular Expression") );
// => true
// => true
网友评论