JavaScript 正则命名分组【推荐】


Posted in Javascript onJune 07, 2018

前言

以往我们只是习惯于通过数组下标来访问正则匹配到的分组,但分组达到4、5个时,标识起来就会非常麻烦。V8早已实现了正则命名分组提案,只是我们很少使用,本文将介绍JS的正则命名分组。

以往的做法

假设要使用正则匹配一个日期的年月日,以往我们会这样做:

const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31

这里有几个缺点:

  • 要找到一个分组的位置,你必须要去数括号的位置,有时嵌套起来会更令人头疼。
  • 后面维护代码的同学阅读起来,还要根据下标找到正则里面对应的括号,并且要再次阅读括号里面的正则才知道含义。
  • 当你调整正则捕获分组的数量、顺序或嵌套时,你必要还要对下面的代码做调整。

所有这些问题,都可以通过正则命名分组来解决。

现在的玩法

现在你只需要给分组里面一个命名标识即可:

(?<year>\d{4})

这里,我们用变量year标记了上一个捕获组#1。 该名称必须是合法的JavaScript标识符。 匹配后,您可以通过matchObj.groups.year访问捕获的字符串。

让我们通过命名分组重写前面的代码:

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // 1999
const month = matchObj.groups.month; // 12
const day = matchObj.groups.day; // 31

如果正则里面有了命名分组,那么匹配结果会多了一个groups 的属性,这个属性中包含了一切命名分组的捕获结果。配合上解构大法使用又是一股清流:

const {groups: {day, year}} = RE_DATE.exec('1999-12-31');
console.log(year); // 1999
console.log(day); // 31

当然,即使你使用了命名分组,那么返回的结果还可以通过以往的数组下标方式访问:

const year2 = matchObj[1]; // 1999
const month2 = matchObj[2]; // 12
const day2 = matchObj[3]; // 31

命名分组具有以下优点:

  • 找到分组的“ID”更容易。
  • 匹配的代码变得自描述性,因为分组的ID描述了捕获的内容。
  • 如果更改分组的顺序,则不必更改匹配的代码。
  • 分组的名称也使正则表达式更易于理解,因为您可以直接看到每个组的用途。

反向引用

反向引用命名分组\k<name>

看下面这个匹配重复单词的例子:

const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
RE_TWICE.test('abc!abc'); // true
RE_TWICE.test('abc!ab'); // false

同时也可以使用以往的反向引用方式:

const RE_TWICE = /^(?<word>[a-z]+)!\1$/;
RE_TWICE.test('abc!abc'); // true
RE_TWICE.test('abc!ab'); // false

replace( )

字符串方法replace()以两种方式支持命名分组:

方式一

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
console.log('1999-12-31'.replace(RE_DATE,
 '$<month>/$<day>/$<year>'));
 // 12/31/1999

如果replace不一定是直接返回新的拼接字符串,那么可以看看下面的办法:

方式二

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
console.log('1999-12-31'.replace(
 RE_DATE,
 (g, y, m, d, offset, input, {year, month, day}) =>
  month+'/'+day+'/'+year));
 // 12/31/1999

看看这replace的callback形参密密麻麻看得心慌慌,很多都用不上,那么我们看看更简单的写法:

console.log('1999-12-31'.replace(RE_DATE,
 (...args) => {
  const {year, month, day} = args.slice(-1)[0];
  return month+'/'+day+'/'+year;
 }));
 // 12/31/1999

这里配合上spread operator直取最后一个参数,再接上一个解构大法,结果又是一股清流。

命名分组没有匹配结果?

如果可选的命名组不被匹配,则其属性值被设置为undefined,但key是仍存在:

const RE_OPT_A = /^(?<as>a+)?$/;
const matchObj = RE_OPT_A.exec('');
// We have a match:
console.log(matchObj[0] === ''); // true
// Group <as> didn't match anything:
console.log(matchObj.groups.as === undefined); // true
// But property as exists:
console.log('as' in matchObj.groups); // true

异常情况

分组名不能有重复项:

/(?<foo>a)(?<foo>b)/ // SyntaxError: Duplicate capture group name

反向引用一个不存在的分组名:

/\k<foo>/u // SyntaxError: Invalid named capture referenced
/\k<foo>/.test("k<foo>") // true, 非 Unicode 下为了向后兼容,k 前面的 \ 会被丢弃

在 reaplce() 方法的替换字符串中引用一个不存在的分组:

"abc".replace(/(?<foo>.*)/, "$<bar>") // SyntaxError: Invalid replacement string
"abc".replace(/(.*)/, "$<bar>") // "$<bar>",不包含命名分组时会向后兼容

最后

  • Chrome60 已支持命名分组
  • 通过babel插件处理兼容问题

babel-plugin-transform-modern-regexp

总结

以上所述是小编给大家介绍的JavaScript 正则命名分组,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
event.srcElement+表格应用
Aug 29 Javascript
Prototype 学习 工具函数学习($w,$F方法)
Jul 12 Javascript
JavaScript对象、属性、事件手册集合方便查询
Jul 04 Javascript
js中查找最近的共有祖先元素的实现代码
Dec 30 Javascript
js css后面所带参数含义介绍
Aug 18 Javascript
jQuery的text()方法用法分析
Dec 20 Javascript
jQuery插件echarts实现的多折线图效果示例【附demo源码下载】
Mar 04 Javascript
jQuery幻灯片插件owlcarousel参数说明中文文档
Feb 27 jQuery
详解创建自定义的Angular Schematics
Jun 06 Javascript
layui默认选中table的CheckBox复选框方法
Sep 19 Javascript
Vue.js计算机属性computed和methods方法详解
Oct 12 Javascript
vue 解决computed修改data数据的问题
Nov 06 Javascript
详解create-react-app 自定义 eslint 配置
Jun 07 #Javascript
vue.js实现标签页切换效果
Jun 07 #Javascript
js数组去重的N种方法(小结)
Jun 07 #Javascript
vue+axios新手实践实现登陆的示例代码
Jun 06 #Javascript
vue2.0实现音乐/视频播放进度条组件
Jun 06 #Javascript
vue实现简单loading进度条
Jun 06 #Javascript
security.js实现的RSA加密功能示例
Jun 06 #Javascript
You might like
PHP缩略图等比例无损压缩,可填充空白区域补充色
2011/06/10 PHP
PHP人民币金额数字转中文大写的函数代码
2013/02/27 PHP
在PHP中运行Linux命令并启动SSH服务的例子
2014/06/12 PHP
PHP之浮点数计算比较以及取整数不准确的解决办法
2015/07/29 PHP
PHP实现连接设备、通讯和发送命令的方法
2015/10/13 PHP
PHP获取用户访问IP地址的5种方法
2016/05/16 PHP
Laravel下生成验证码的类
2017/11/15 PHP
基于jquery的监控数据是否发生改变
2011/04/11 Javascript
Array, Array Constructor, for in loop, typeof, instanceOf
2011/09/13 Javascript
获取内联和链接中的样式(js代码)
2013/04/11 Javascript
前端必备神器 Snap.svg 弹动效果
2014/11/10 Javascript
JavaScript插件化开发教程 (一)
2015/01/27 Javascript
angular实现spa单页面应用实例
2017/07/10 Javascript
JS常见构造模式实例对比分析
2018/08/27 Javascript
详解使用jest对vue项目进行单元测试
2018/09/07 Javascript
微信小程序中的canvas 文字断行和省略号显示功能的处理方法
2018/11/14 Javascript
微信小程序中如何计算距离某个节日还有多少天
2019/07/15 Javascript
react native 仿微信聊天室实例代码
2019/09/17 Javascript
[13:18]《一刀刀一天》之DOTA全时刻21:详解TI新赛制 A队再露獠牙
2014/06/24 DOTA
[00:47]TI7不朽珍藏III——沙王不朽展示
2017/07/15 DOTA
[03:21]【TI9纪实】Old Boys
2019/08/23 DOTA
python实现读取命令行参数的方法
2015/05/22 Python
Python中如何获取类属性的列表
2016/12/26 Python
python2.6.6如何升级到python2.7.14
2018/04/08 Python
python 列表删除所有指定元素的方法
2018/04/19 Python
对Python定时任务的启动和停止方法详解
2019/02/19 Python
解决torch.autograd.backward中的参数问题
2020/01/07 Python
python3从网络摄像机解析mjpeg http流的示例
2020/11/13 Python
Made in Design德国:设计师家具、灯具和装饰
2019/10/31 全球购物
新员工培训个人的自我评价
2013/10/09 职场文书
我的网上商城创业计划书
2013/12/26 职场文书
英语简历自我评价
2014/01/26 职场文书
2014年学校党建工作汇报材料
2014/11/02 职场文书
企业内部管理控制:采购授权审批制度范本
2020/01/19 职场文书
Memcached介绍及php-memcache扩展安装
2021/04/01 PHP
Python字符串对齐方法使用(ljust()、rjust()和center())
2021/04/26 Python