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 相关文章推荐
原生js 秒表实现代码
Jul 24 Javascript
基于jquery扩展漂亮的下拉框可以二次修改
Nov 19 Javascript
JavaScript数据类型检测代码分享
Jan 26 Javascript
JavaScript使用function定义对象并调用的方法
Mar 23 Javascript
JavaScript实现将UPC转换成ISBN的方法
May 26 Javascript
js实现滚动条滚动到页面底部继续加载
Dec 19 Javascript
微信小程序 Audio API详解及实例代码
Sep 30 Javascript
Vue.js实现移动端短信验证码功能
Mar 29 Javascript
ES6 系列之 Generator 的自动执行的方法示例
Oct 19 Javascript
详解用async/await来处理异步
Aug 28 Javascript
JavaScript判断数组类型的方法
Oct 23 Javascript
微信小程序的引导页实现代码
Jun 24 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实现网上点歌(二)
2006/10/09 PHP
一段php加密解密的代码
2007/07/16 PHP
php xml文件操作实现代码(二)
2009/03/20 PHP
PHP限制页面只能在微信自带浏览器访问的代码
2014/01/15 PHP
smarty模板中拼接字符串的方法
2014/02/14 PHP
php截取字符串之截取utf8或gbk编码的中英文字符串示例
2014/03/12 PHP
Colortip基于jquery的信息提示框插件在IE6下面的显示问题修正方法
2010/12/06 Javascript
js实现图片拖动改变顺序附图
2014/05/13 Javascript
JavaScript实现找出数组中最长的连续数字序列
2014/09/03 Javascript
jQuery结合HTML5制作的爱心树表白动画
2015/02/01 Javascript
深入理解JavaScript系列(43):设计模式之状态模式详解
2015/03/04 Javascript
JavaScript实现标题栏文字轮播效果代码
2015/10/24 Javascript
js删除Array数组中指定元素的两种方法
2016/08/03 Javascript
Bootstrap和Java分页实例第二篇
2016/12/23 Javascript
JS ES6中setTimeout函数的执行上下文示例
2017/04/27 Javascript
Vue.js常用指令之循环使用v-for指令教程
2017/06/27 Javascript
VUEX-action可以修改state吗
2019/11/19 Javascript
javascript实现弹幕墙效果
2019/11/28 Javascript
Vue组件通信中非父子组件传值知识点总结
2019/12/05 Javascript
react PropTypes校验传递的值操作示例
2020/04/28 Javascript
Python设计实现的计算器功能完整实例
2017/08/18 Python
Python图像处理之图像的缩放、旋转与翻转实现方法示例
2019/01/04 Python
Python使用jpype模块调用jar包过程解析
2020/07/29 Python
python开发入门——set的使用
2020/09/03 Python
python 判断一组数据是否符合正态分布
2020/09/23 Python
CSS3制作Dropdown下拉菜单的方法
2015/07/18 HTML / CSS
Bitiba意大利:在线宠物商店
2020/10/31 全球购物
提高EJB性能都有哪些技巧
2012/03/25 面试题
车间工艺员岗位职责
2013/12/09 职场文书
淘宝网店营销策划书
2014/01/11 职场文书
最新奶茶店创业计划书
2014/01/25 职场文书
优秀体育委员自荐书
2014/01/31 职场文书
借款担保书范文
2014/05/13 职场文书
2014年敬老院工作总结
2014/12/08 职场文书
关于感恩的歌曲整理(8首)
2019/08/14 职场文书
磁贴还没死, 微软Win11可修改注册表找回Win10开始菜单
2021/11/21 数码科技