正则的扩展

news2024/11/24 3:02:07

RegExp()

es5中,RegExp的构造函数参数有两种情况
1、字符串
2、正则表达式

// 第一种情况
let regex = new RegExp('abc', 'i')

// 第二种情况
let regex2 = /abc/i

这两种情况是等价的

let s = 'abc'
regex.test(s) == regex2.test(s); // true

在es5中这两种方式不能混用,如果第一个参数是一个正则,第二个是修饰会报错
let regex3 = new RegExp(/abc/,'i') // 报错

es6改变了这种行为,如果第一个是正则,第二个参数可以使用修饰符,并且返回的正则表达式会忽略原有的正则表达式修饰符,只使用新指定的修饰符。

let regex4 = new RegExp(/abc/ig, 'i')

在这里,第二个参数i会把原有的正则修饰符ig覆盖,最后的结果为/abc/i


u 修饰符

es6对正则表达式添加了u修饰符,表示为Unicode模式,用来处理大于\uFFFFUnicode字符

/^\uD83D/u.test('\uD83D\uDC2A');  // false

这里加上了u.所以变成了es6支持,将\uD83D\uDC2A转译为一个字符,与\uD83D不匹配,所以返回false

/^\uD83D/.test('\uD83D\uDC2A'); // true  

这里没有加u.es5支持,无法识别4个字节的UTF-16编码。会将\uD83D\uDC2A识别为两个字符,比对的时候其中的字符匹配,所以返回true


点字符 .

点字符在正则表达式中,表示除了换行符以外的任意单个字符,但对于码点大于0xFFFF的字符,点字符串无法识别,必须前面加上u修饰符

let z = '正'
/^.$/.test(z);   // true
/^.$/u.test(z);  // true

Unicode 字符表示法

es6新增了大括号表示unicode字符,这种字符在正则中必须使用 u 修饰符才能识别,否则会被解读为量词,量词是无法识别大于0xFFFFunicode字符的。

/\u{61}/.test('a'); // false
/\u{61}/u.test('a'); // true

i 修饰符

i 修饰符为不区分大小写,对于大于0xFFFFunicode的修饰符,后面需要加上 u

/[a-z]/i.test('\u212A'); // false 
/[a-z]/iu.test('\u212A'); // true

y 修饰符

y修饰符,意为粘连(sticky)修饰符
在正则匹配中,g为全局匹配且没有位置限制
y在正则匹配中,有位置限制,必须在上一次匹配完后的下一个字符串的第一位开始匹配。

let a = 'aaa-aa-a'
let r = /a+/y
let r2 = /a+/g
// 第一次匹配
r.exec(a); // aaa
r2.exec(a); // aaa
// 第二次匹配
r.exec(a); // null  
r2.exec(a); // aa  

y为粘连,上一次匹配完后的下一个字符串第一位,第一位是:-无法匹配上,解决的方法:其实只需要修改一下正则保证每次匹配上就行了 /a+-/y
g为全局匹配没有位置限制

RegExp.prototype.sticky
来检查是否设置了 y 修饰符

let a1 = /heelo\d/y
console.log(a1.sticky); // true

检测正则表达式修饰符以及正文

  • source 返回正则匹配规则
  • flags 返回正则的修饰符
let rul = /abc/ig
console.log(rul.source); // abc
console.log(rul.flags); // ig

s 修饰符 : dotAll模式

正则表达式中,点(.)是一个特殊的字符,代表任意字符,但是有两种例外
第一种:四个字节的UTF-16字符,这个使用 u 修饰符解决
第二种:行终止符,使用 s 修饰符解决

行终止符,就是该字符表示一行的终结,下面四个字符属于“行终止符”

  • U+000A 换行符(\n
  • U+000D 回车符(\r
  • U+2028 行分隔符(line separator)
  • U+2029 段分隔符(paragraph separator)
 let f = /foo.bar/.test('foo\nbar')
console.log(f); // false // 因为.不匹配 \n ,所以正则表达式返回false

// 解决方法 : s 修饰符
/* 使用s修饰符,可以使 . 匹配任意单个字符 */
let f2 = /foo.bar/s.test('foo\nbar')
console.log(f2); // true

这种s修饰符的模式被称为dotAll模式,dot就是代表一切字符。
所以,正则表达式还引入了dotAll模式,检查该表达式是否开启了dotAll模式。

let f3 = /foo.bar/s
console.log(f3.dotAll); // true  // 开始了dotAll模式

先行断言和后行断言

先行断言

先行断言指的是,x在y的前面才匹配
语法:/x(?=y)/ x在y符号前才匹配

let look = '100% 东方不败'
/\d+(?=%)/.exec(look); // 100  // 数字在百分号前面才匹配

let look2 = '100! 东方不败'
console.log(/\d+(?=%)/.exec(look2));  // null 没有匹配到%前的数字

后行断言

与先行断言相反,x在y的后面时才匹配
语法:/(?<=y)x/ 说明: ? 后面跟 <= 条件y

let look3 = '东方不败 $100 西方求败'
/(?<=\$)\d+/.exec(look3); // 100  表示在\$后的字符才会被匹配

注意 : 先行断言和后行断言的条件是不计入返回结果的


具名组匹配

正则表达式使用圆括号进行组的匹配,每组圆括号代表着一个匹配,匹配结果可以从组中提取出来

let rul = /(\d{4})-(\d{2})-(\d{2})/
let r = rul.exec('2022-12-13')
console.log(r[1]);  // 2022
console.log(r[2]);  // 12
console.log(r[3]);  // 13

虽然结果可以从组中提取出来,但它是通过下标提取的,如果组的顺序发生改变,那么下标也需要做对应更改,其实是不太方便的,对此es2018引入了"具名组匹配",可以给组取别名,通过别名提取结果
语法:(?<别名>正则)

let rul2 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
let r2 = rul2.exec('2022-12-13')
console.log(r2.groups.year);  // 2022
console.log(r2.groups.month);  // 12
console.log(r2.groups.day);  // 13
console.log(r2.groups.minute);  // undefined  如果没有比配,那么对象属性为undefined

解构赋值和替换

通过上面的具名组匹配,给组取别名后,在正则的groups中,匹配的属性实际上是一个对象,通过解构赋值可以直接从匹配结果上为变量赋值。

. 可以匹配任意字符,查找单个字符,除了换行和行结束符。
n* 匹配任何包含零个或多个 n 的字符串。

解构:

let {groups : {hours,minute}} = /^(?<hours>.*):(?<minute>.*)/.exec('12:49')
console.log(hours,minute);  // 12  49  // 通过解构赋值提取

替换
字符串替换时,使用$<组名>进行替换

  • 将匹配的字符串位置替换
  • 不影响原正则表达式
let rul4 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u

console.log('2022-12-13'.replace(rul4,'$<day>/$<month>/$<year>')); // 13-12-2022

console.log(rul4);  // /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u

replace()的第二个参数可以是一个函数

let data = '2022-12-13'.replace(rul4,(matched,params1,param2,params3,position,sources,groups)=>{
        let {day,month,year} = groups;
        return `${day}/${month}/${year}`
       })
console.log(data);   // 13-12-2022

说明:

  • matched // ‘2022-12-13’ 匹配结果
  • params1 // 第一个组匹配2022
  • param2 // 第一个组匹配12
  • params3 // 第一个组匹配13
  • position // 匹配开始的位置 0
  • sources // 原字符串 2022-12-13
  • groups // 具名组构成的一个对象 {year, month, day}

引用

如果要在正则表达式内部引用某个“具名组匹配”,可以使用 \k<组名> 的写法

let str = /^(?<word>[a-z]+)!\k<word>$/
str.test('abc!abc');  // true  引用了具名匹配,前后都是abc,前后字符一致
str.test('abc!ab');   // false 引用了具名匹配,前后字符不匹配,但是第二个少一个c

其实可以这么理解,引用就是将前面定义好的组,拿过来复用。

数字引用
首先需要明确分组的概念,即正则中的()中的内容是一个分组,里面的内容作为一个整体引用。如果在分组后面接上 \数字,表示匹配第几个分组

let str2 = /^(\d{2})([a-z]+)\1$/
console.log(str2.test('11abcd'));  // false 
console.log(str2.test('11aa11'));  // true

第一个输出:问题出在结尾是英文,这里结尾使用了\数字1表示匹配第一个分组,第一个分组是必须是2个数字,这里的结尾用的英文所以返回false
第二个输出:true,其实这时的正则为/^(\d{2})([a-z]+)(\d{2})$/\1引用了第一个组


具名匹配的引用和数字引用可以同时使用

let str3 = /^(?<word>[a-z]+)-(\d{2})-\k<word>-\2$/
str3.test('a-11-a-11'); // true
str3.test('a-11-a-aa'); // false

第一个输出:这里使用了引用以及数字引用
第二个输出:false, 结尾通过数字引用后,应该为数字\d{2}


d 修饰符:正则匹配索引

es2022新增d修饰符,可以在exec()match()的返回结果添加indices属性,在该属性上可以拿到匹配的开始位置和结束位置,下标从0开始

let text = 'abcdefg'
let te = /bc/d
let result = te.exec(text)

result.index;  // 1   拿到bc匹配的起始位置,下标为1
result.indices;  // [1,3]  拿到bc匹配的开始和结束位置的下一个字符的位置

非常重要!!!这里需要注意的是,匹配的字符串开始位置是字符串的第一个值,匹配的结束位置,并不在返回结果中,正确来说,匹配的结束位置是匹配字符串的末尾的下一个位置,如果这一句不理解,下面的内容将会很难理解

如果正则中包含组匹配,那么indices属性对应的数组就会包含多个成员,并且提供每个组的开始位置和结束位置

let text2 = 'abccdef'
let te2 = /bc+(de)/d
let result2 = te2.exec(text2)
console.log(result2.indices);  // [1,6][4,6] 
  • 这里的匹配并不是单个的匹配,而是整体,最外层的bc其实不参与单独的匹配,而是放到bcde整体中,所以第一个数组打印的是1,6b的下标为1e的下一个字符的下标为6`
  • 组会单独进行匹配,d的下标为4e的下一个字符的下标为6

多个组匹配以及下标

let text3 = 'abccdefgh'
let te3 = /bc+(de(fg))/d
let result3 = te3.exec(text3)

result3.indices;  // [1,8][4,8][6,8] 

匹配的顺序:bcdefgdefgfg,对应的打印结果[1,8][4,8][6,8]


如果正则表达式包含具名匹配,那么indices.groups的属性会是一个对象,可以从该对象获取具名组匹配的开始位置和结束位置

let text4 = 'abcdefgh'
let te4 = /bc+(?<word>de)/d  // 具名组<word>
let result4 = te4.exec(text4)

result4.indices; // [1,5][3,5]
result4.indices.groups; // {word : [3,5]}

在这里插入图片描述
在这里插入图片描述

如果未匹配上则打印undefined


String.prototype.matchAll()

matchAll()可以一次性取出所有匹配,返回的是遍历器(Iterator)而不是数组

let strings = 'test1test2test3';
let regex = /t(e)(st(\d?))/g;

for(let match of strings.matchAll(regex)){
   console.log(match);  // 返回所有匹配
  }

在这里插入图片描述

转为数组的方法一

[...strings.matchAll(regex)]; // 返回所有匹配,结果为数组

转为数组的方法二

Array.from(strings.matchAll(regex)); // 返回所有匹配,结果为数组

在这里插入图片描述


案例源码:https://gitee.com/wang_fan_w/es6-science-institute

如果觉得这篇文章对你有帮助,欢迎点亮一下star哟

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/89762.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图解设计模式:动动手玩转迭代器模式

前言 &#x1f4e3; &#x1f4e3; &#x1f4e3; &#x1f4e2;&#x1f4e2;&#x1f4e2; ☀️☀️点开就是缘分认识一下&#xff0c;我是小冷。是一个兴趣驱动自学练习两年半的的Java工程师。 &#x1f4d2; 一位十分喜欢将知识分享出来的Java博主⭐️⭐️⭐️&#xff0c;…

JavaSE04

形参或者返回值是类名的话&#xff1a;方法的形参是类名&#xff0c;其实是需要的类名的对象。方法的返回值是类名的话&#xff0c;其实返回的是对象。 接口名 作为形参或者 方法的返回值&#xff1a;主要对应的是接口的实现类对象。 内部类的特点:内部类可直接访问外部类的成…

Unity中的C#脚本都继承了Monobehaviour类(Monobehaviour类的分析)

1、Monobehaviour类 Unity中的脚本都是继承Monobehaviour&#xff0c;定义了脚本的基本行为。必然是继承. 我们之前所熟知的声明周期函数。 除了必然事件&#xff0c;还定义了对各种特定事件的相应函数&#xff0c;均已On开头 MonoBehaviour中的事件响应函数都是已On开头的&am…

1 CPP11基础篇(快速学习)

另外还有 long double 不少于double 不低于double 注意&#xff1a; 在VS和Linux中 long double占用的内存空间分别是8和16个字节 c11原始字面量 void的关键字 在C中&#xff0c;void表示为无类型 主要有3个用途 1、函数的返回值用void 表示函数没有返回值 2、函数的参数填…

修改oracle11g的awr快照参数

1、select * from v$version; 2、select * from dba_hist_wr_control; 检查当前系统的保留时间为8天,1小时采样一次. 3、这里设置每半个小时收集一次&#xff0c; 收集到的数据保留15天&#xff0c;单位都是秒。 exec dbms_workload_repository.modify_snapshot_settings(ret…

[附源码]计算机毕业设计的图书互换系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

web前端网页设计期末课程大作业:旅游网页主题网站设计——三亚旅游网页设计(6个页面) HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

类装载器ClassLoader 、执行引擎ExecutionEngine【Java培训】

1. 定义 负责加载class文件&#xff0c;class文件在文件开头有特定的文件标示&#xff0c;并且ClassLoader只负责class文件的加载&#xff0c;至于它是否可以运行&#xff0c;则由Execution Engine决定。 Java培训 2. 类加载器分类 虚拟机自带的加载器启动类加载器&#xff0…

【现代机器人学】学习笔记六:闭链运动学

这一章的内容主要讲并联机器人的相关算法&#xff0c;内容在全书中属于比较少&#xff0c;仅仅介绍概念的章节。 恰好部门中有一位同事就是专门做并联机器人出身的博士&#xff0c;也请他帮忙看了一下内容&#xff0c;但他觉得写书的这个人可能也不是非常懂并联机器人&#xf…

Java集合——Collection

Collection集合 Collection接口下主要有三大子接口 List Queue Set 1. List List是有序可重复集合&#xff0c;根据索引下标来访问元素 List接口常见的三个实现类&#xff1a;ArrayList 、LinkedList、Vector 特点&#xff1a; 集合中的元素允许重复集合中的元素有序&…

UE4 Cook指定平台资源

内容烘焙 | 虚幻引擎文档 (unrealengine.com) 虚幻引擎以内部使用的特定格式存储内容资源&#xff0c;如PNG用于存储纹理 数据&#xff0c;WAV用于音频数据。但是&#xff0c;该内容需要针对各平台转换为不同的格式&#xff0c; 因为平台使用专有格式&#xff0c;或者平台不支…

Revit中“幕墙网格”编辑斜向网格和柱断墙梁

一、Revit中“幕墙网格”编辑斜向网格 我们可以为幕墙添加任意间距的水平和垂直的网格线&#xff0c;但是对于斜向网格线我们却只能通过设置其实例属性中的角度来控制其生成一系列等间距的斜向网格&#xff0c;那么如果遇到不等间距的斜向网格线我们应该如何绘制呢? 首先通过设…

博宜OJ练习题基础题目中个别问题的题(欢迎一起讨论)

中国博宜练习题个别问题&#xff0c;望讨论前言题目1解题思路提交后正确代码&#xff1a;个人写的错误代码题目2正确代码2个人写的错误代码2以上是个人目前遇到的两个问题&#xff0c;不知道是直接使用“max”函数的问题 还是什么&#xff0c;如果是“max”函数问题第一个测试点…

多线程与高并发(二)

【锁的底层实现】&#xff1a; 【 简介 】&#xff1a; JDK早期的时候是重量级的 &#xff0c; 会去找OS系统申请锁 &#xff0c;效率非常低。 后来的改进——《锁升级过程》。 【锁升级过程】&#xff1a; sync( Object ) 【偏向锁】&#xff1a; markword记录这个线程ID&…

[附源码]Python计算机毕业设计Django基于JEE平台springbt技术的订餐系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

以太网 MSTP多实例生成树的简介、MSTP与RSTP、STP之间的联系、MSTP BPDU格式介绍、MSTP关键名词介绍)

2.12.0 以太网 MSTP多实例生成树&#xff08;简介、MSTP与RSTP、STP联系、MSTP BPDU格式、MSTP关键名词介绍&#xff09; 主要参考&#xff1a;华为S2750, S5700, S6700 V200R005(C00&C01&C02&C03) 产品文档 《MSTP基本概念》 MSTP快速生成树简介MSTP关键名词介绍1…

springboot+mybatis+mysql实现的个人博客管理系统(功能包含登录,栏目管理、文章管理、评论管理、系统设置、用户管理、发布博客、评论等)

博客目录springbootmybatis实现的个人博客管理系统实现功能截图系统功能使用技术代码完整源码springbootmybatis实现的个人博客管理系统 本系统是一个个人博客管理系统&#xff0c;比较新的框架springbootmybatis实现&#xff0c;分为普通用户和管理员&#xff0c;普通用户可以…

【软件测试】测试人接手新应用程序怎么测?看看这几个方法......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 应用程序很复杂的&a…

三、数据链路层(三)差错控制

目录 3.1检错编码 3.1.1奇偶校验码 3.1.2循环冗余码&#xff08;CRC&#xff09; 3.2纠错编码 3.2.1海明码 传输差错可分为两种&#xff1a; 位错&#xff1a;帧中某些位出现了差错&#xff0c;也称比特差错、误码。帧错&#xff1a;帧的丢失、重复或失序等错误。 通常利…

面试题:数据结构和算法

1、时间复杂度解释一下 算法的时间复杂度&#xff0c;用来度量算法的运行时间&#xff0c;记作: T(n) O(f(n))。它表示随着 输入大小n 的增大&#xff0c;算法执行需要的时间的增长速度可以用 f(n) 来描述。 当 T(n) c&#xff0c;c 为一个常数的时候&#xff0c;我们说这个…