JavaScript正则表达式的分组匹配详解


Posted in Javascript onFebruary 13, 2016

分组

下面的正则表达式可以匹配kidkidkid:

/kidkidkid/

而另一种更优雅的写法是:

/(kid){3}/

这里由圆括号包裹的一个小整体称为分组。

候选

一个分组中,可以有多个候选表达式,用|分隔:

var reg = /I love (him|her|it)/;

reg.test('I love him')  // true 
reg.test('I love her')  // true
reg.test('I love it')  // true
reg.test('I love them') // false

这里的|相当于“或”的意思。

捕获与引用

被正则表达式匹配(捕获)到的字符串会被暂存起来。其中,由分组捕获的串会从1开始编号,于是我们可以引用这些串:

var reg = /(\d{4})-(\d{2})-(\d{2})/
var date = '2010-04-12'
reg.test(date)

RegExp.$1 // 2010
RegExp.$2 // 04
RegExp.$3 // 12

$1引用了第一个被捕获的串,$2是第二个,依次类推。

与replace配合

String.prototype.replace方法的传参中可以直接引用被捕获的串。比如我们想将日期12.21/2012改为2012-12-21:

var reg = /(\d{2}).(\d{2})\/(\d{4})/
var date = '12.21/2012'

date = date.replace(reg, '$3-$1-$2') // date = 2012-12-21

顺道一提,给replace传迭代函数,有时能优雅地解决一些问题。

将违禁词转换为等字数的星号是一个常见功能。比如文本是kid is a doubi,其中kid与doubi是违禁词,那么转换后应该为*** is a *****。我们可以这么写:

var reg = /(kid|doubi)/g
var str = 'kid is a doubi'

str = str.replace(reg, function(word){
  return word.replace(/./g, '*')
})

嵌套分组的捕获

如果碰到类似/((kid) is (a (doubi)))/的嵌套分组,捕获的顺序是什么?来试试:

var reg = /((kid) is (a (doubi)))/
var str = "kid is a doubi"

reg.test( str ) // true

RegExp.$1 // kid is a doubi
RegExp.$2 // kid
RegExp.$3 // a doubi
RegExp.$4 // doubi

规则是以左括号出现的顺序进行捕获。

反向引用

正则表达式里也能进行引用,这称为反向引用:

var reg = /(\w{3}) is \1/

reg.test('kid is kid') // true
reg.test('dik is dik') // true
reg.test('kid is dik') // false
reg.test('dik is kid') // false

\1引用了第一个被分组所捕获的串,换言之,表达式是动态决定的。

注意,如果编号越界了,则会被当成普通的表达式:

var reg = /(\w{3}) is \6/;

reg.test( 'kid is kid' ); // false
reg.test( 'kid is \6' );  // true

分组的类型

分组有四种类型:

捕获型

 - ()
非捕获型

- (?:)
正向前瞻型 - (?=)
反向前瞻型 - (?!)
我们之前说的都是捕获型分组,只有这种分组会暂存匹配到的串。

非捕获型分组

有时候,我们只是想分个组,而没有捕获的需求,则可以使用非捕获型分组,语法为左括号后紧跟?::

var reg = /(?:\d{4})-(\d{2})-(\d{2})/
var date = '2012-12-21'
reg.test(date)

RegExp.$1 // 12
RegExp.$2 // 21

这个例子中,(?:\d{4})分组不会捕获任何串,所以$1为(\d{2})捕获的串。

正向与反向前瞻型分组

就好像你站在原地,向前眺望:

正向前瞻型分组 - 你前方是什么东西吗?
负向前瞻型分组 - 你前方不是什么东西吗?
太拗口了,我喜欢称之为肯定表达式与否定表达式。先举个正向前瞻的例子:

var reg = /kid is a (?=doubi)/

reg.test('kid is a doubi') // true
reg.test('kid is a shabi') // false

kid is a 后面跟着什么?如果是doubi才能匹配成功。

而负向前瞻则刚好相反:

var reg = /kid is a (?!doubi)/

reg.test('kid is a doubi') // false
reg.test('kid is a shabi') // true

如果前瞻型分组也不会捕获值。那么它与非捕获型的区别是什么?看例子:

var reg, str = "kid is a doubi"

reg = /(kid is a (?:doubi))/
reg.test(str)
RegExp.$1 // kid is a doubi

reg = /(kid is a (?=doubi))/
reg.test(str)
RegExp.$1 // kis is a

可见,非捕获型分组匹配到的串,仍会被外层的捕获型分组捕获到,但前瞻型却不会。当你需要参考后面的值,又不想连它一起捕获时,前瞻型分组就派上用场了。

最后,JS不支持后瞻型分组。

Javascript 相关文章推荐
用JavaScript脚本实现Web页面信息交互
Dec 21 Javascript
JQuery+DIV自定义滚动条样式的具体实现
Jun 25 Javascript
js 阻止子元素响应父元素的onmouseout事件具体实现
Dec 23 Javascript
使用JavaScript和C#中获得referer
Nov 14 Javascript
Bootstrap教程JS插件弹出框学习笔记分享
May 17 Javascript
JS表格组件神器bootstrap table详解(强化版)
May 26 Javascript
js判断请求的url是否可访问,支持跨域判断的实现方法
Sep 17 Javascript
jQuery中值得注意的trigger方法浅析
Dec 12 Javascript
ES6生成器用法实例分析
Apr 10 Javascript
vue实现类似淘宝商品评价页面星级评价及上传多张图片功能
Oct 29 Javascript
小程序组件之自定义顶部导航实例
Jun 12 Javascript
Vue.js 实现地址管理页面思路详解(地址添加、编辑、删除和设置默认地址)
Dec 11 Javascript
js HTML5 Ajax实现文件上传进度条功能
Feb 13 #Javascript
js随机生成26个大小写字母
Feb 12 #Javascript
jquery实现具有嵌套功能的选项卡
Feb 12 #Javascript
基于jquery实现动态竖向柱状条特效
Feb 12 #Javascript
原生javascript实现自动更新的时间日期
Feb 12 #Javascript
原生javascript实现图片无缝滚动效果
Feb 12 #Javascript
JavaScript实现点击单元格改变背景色的方法
Feb 12 #Javascript
You might like
zf框架的registry(注册表)使用示例
2014/03/13 PHP
Yii入门教程之Yii安装及hello world
2014/11/25 PHP
使用laravel和ajax实现整个页面无刷新的操作方法
2019/10/03 PHP
Javascript图像处理—平滑处理实现原理
2012/12/28 Javascript
深入理解Javascript中的循环优化
2013/11/09 Javascript
js生成随机数的方法实例
2015/10/16 Javascript
再谈JavaScript异步编程
2016/01/27 Javascript
jQuery常用知识点总结以及平时封装常用函数
2016/02/23 Javascript
JavaScript笔记之数据属性和存储器属性
2016/03/31 Javascript
全面理解闭包机制
2016/07/11 Javascript
Vuex简单入门
2017/04/19 Javascript
Angularjs中数据绑定的实例详解
2017/08/25 Javascript
NodeJS收发GET和POST请求的示例代码
2017/08/25 NodeJs
详解从Vue.js源码看异步更新DOM策略及nextTick
2017/10/11 Javascript
ES6知识点整理之对象解构赋值应用示例
2019/04/17 Javascript
python实现简单的socket server实例
2015/04/29 Python
在Python中处理字符串之ljust()方法的使用简介
2015/05/19 Python
python 截取 取出一部分的字符串方法
2017/03/01 Python
tensorflow 打印内存中的变量方法
2018/07/30 Python
使用Python和Prometheus跟踪天气的使用方法
2019/05/06 Python
python 计算数据偏差和峰度的方法
2019/06/29 Python
我们为什么要减少Python中循环的使用
2019/07/10 Python
python 并发下载器实现方法示例
2019/11/22 Python
如何使用Django Admin管理后台导入CSV
2020/11/06 Python
使用django自带的user做外键的方法
2020/11/30 Python
matplotlib 画动态图以及plt.ion()和plt.ioff()的使用详解
2021/01/05 Python
HTML5之WebGL 3D概述(上)—WebGL原生开发开启网页3D渲染新时代
2013/01/31 HTML / CSS
HTML5单页面手势滑屏切换原理分析
2017/07/10 HTML / CSS
瑞士香水购物网站:Parfumcity.ch
2017/01/14 全球购物
法律工作求职自荐信
2013/10/31 职场文书
你懂得怎么写自荐信吗?
2013/12/27 职场文书
委托证明模板
2014/09/16 职场文书
客服专员岗位职责
2015/02/10 职场文书
十月围城观后感
2015/06/08 职场文书
2015教师节通讯稿
2015/07/20 职场文书
会议室管理制度范本
2015/08/06 职场文书