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 相关文章推荐
jquery改变disabled的boolean状态的三种方法
Dec 13 Javascript
javascript实现youku的视频代码自适应宽度
May 25 Javascript
javascript图片预加载实例分析
Jul 16 Javascript
jquery uploadify如何取消已上传成功文件
Feb 08 Javascript
angularjs指令之绑定策略(@、=、&)
Apr 13 Javascript
JavaScript贪吃蛇小组件实例代码
Aug 20 Javascript
vue编译打包本地查看index文件的方法
Feb 23 Javascript
简化vuex的状态管理方案的方法
Jun 02 Javascript
layui关闭层级、简单监听的实例
Sep 06 Javascript
JS实现拼图游戏
Jan 29 Javascript
js实现小球在页面规定的区域运动
Jun 16 Javascript
antd多选下拉框一行展示的实现方式
Oct 31 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
Syphon 虹吸式咖啡壶冲煮–拨动法
2021/03/03 冲泡冲煮
10条PHP编程习惯助你找工作
2008/09/29 PHP
Laravel 5框架学习之Laravel入门和新建项目
2015/04/07 PHP
PHP多线程模拟实现秒杀抢单
2018/02/07 PHP
jQuery帮助之筛选查找 children([expr])
2011/01/31 Javascript
js分解url参数(面向对象-极简主义法应用)
2012/08/09 Javascript
javascript高级程序设计第二版第十二章事件要点总结(常用的跨浏览器检测方法)
2012/08/22 Javascript
php对mongodb的扩展(初识如故)
2012/11/11 Javascript
JavaScript中window、doucment、body的解释
2013/08/14 Javascript
js中传递特殊字符(+,&)的方法
2014/01/16 Javascript
一个CSS+jQuery实现的放大缩小动画效果
2014/02/19 Javascript
我的Node.js学习之路(三)--node.js作用、回调、同步和异步代码 以及事件循环
2014/07/06 Javascript
javascript获取当前的时间戳的方法汇总
2015/07/26 Javascript
Javascript之Date对象详解
2016/06/07 Javascript
jQuery stop()用法实例详解
2016/07/28 Javascript
JS数组去掉重复数据只保留一条的实现代码
2016/08/11 Javascript
微信小程序进行微信支付的步骤昂述
2016/12/01 Javascript
浅谈Javascript事件对象
2017/02/05 Javascript
微信小程序中显示html格式内容的方法
2017/04/25 Javascript
如何获取TypeScript的声明文件.d.ts
2018/05/01 Javascript
简单实现节流函数和防抖函数过程解析
2019/10/08 Javascript
[03:26]《DAC最前线》之EG经理自述DOTA2经历
2015/02/02 DOTA
python通过opencv实现批量剪切图片
2017/11/13 Python
python中找出numpy array数组的最值及其索引方法
2018/04/17 Python
python使用pygame模块实现坦克大战游戏
2020/03/25 Python
Python zip函数打包元素实例解析
2019/12/11 Python
零基础学python应该从哪里入手
2020/08/11 Python
使用python将微信image下.dat文件解密为.png的方法
2020/11/30 Python
阿拉伯世界最大的电子卖场:Souq埃及
2016/08/01 全球购物
软件测试面试题
2015/10/21 面试题
AJAX的优缺点都有什么
2015/08/18 面试题
中医药大学市场营销专业自荐信
2013/09/29 职场文书
幼儿园小班家长寄语
2014/04/02 职场文书
学习型党组织建设经验材料
2014/05/26 职场文书
校园标语大全
2014/06/19 职场文书
使用SQL实现车流量的计算的示例代码
2022/02/28 SQL Server