正则表达式生成器字母接数字(正则的扩展详解)
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模式 ,用来处理大于\uFFFF的Unicode字符
/^\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); // trueUnicode 字符表示法
es6新增了大括号表示unicode字符 ,这种字符在正则中必须使用 u 修饰符才能识别 ,否则会被解读为量词 ,量词是无法识别大于0xFFFF的unicode字符的 。
/\u{61}/.test(a); // false /\u{61}/u.test(a); // truei 修饰符
i 修饰符为不区分大小写 ,对于大于0xFFFF的unicode的修饰符 ,后面需要加上 u
/[a-z]/i.test(\u212A); // false /[a-z]/iu.test(\u212A); // truey 修饰符
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); // aay为粘连 ,上一次匹配完后的下一个字符串第一位 ,第一位是:-无法匹配上,解决的方法:其实只需要修改一下正则保证每次匹配上就行了 /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); // igs 修饰符 : 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})/ureplace()的第二个参数可以是一个函数
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 // 具名组构成的一个对象引用
如果要在正则表达式内部引用某个“具名组匹配 ” ,可以使用 \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,6,b的下标为1 ,e的下一个字符的下标为6` 组会单独进行匹配 ,d的下标为4 ,e的下一个字符的下标为6多个组匹配以及下标
let text3 = abccdefgh let te3 = /bc+(de(fg))/d let result3 = te3.exec(text3) result3.indices; // [1,8][4,8][6,8]匹配的顺序:bcdefg 、defg 、fg ,对应的打印结果[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哟
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!