前言
关于正则表达式位置匹配的文章有很多,以下为笔者学习过程中的总结
1、位置匹配知多少?
在正则表达式中和位置有直接或间接关系的有,修饰符 “m” “y”,锚点,边界词\b,反向引用\N,前瞻断言与后瞻断言,正则表达式和字符串的方法,如:search,match,replace,exec等都能和位置下标扯上关系。
2、锚点与边界词\b
插入符号 ^ 表示匹配输入的开头
美元符号 $ 表示匹配输入的结尾
// 示例
const str = "Singh handsome";
// 表示开头为S
/^S.*/.test(str1) // true
// 表示结尾为e
/.*e$/.test(str1) // true
插入符号 ^ 要放在模式的开头,美元符号 $ 要放在模式的结尾
锚点既可以用做单一字符类也可以用做分组和集合范围
锚点与修饰符 “m”
修饰符 “m” 表示多行搜索,也就是每一行的开头和结尾都会匹配到
const str = `Singh
hand
Some`;
str.match(/^S.*/gm) // ['Singh ', 'Some']
当然对于简单的开头/结尾我们可以使用 startsWith/endsWith 方法就好了
3.边界词\b与反向引用\N
边界词\b不是[\b]哦,[\b]表示一个退格倒也能和位置扯上一点关系。
从MDN的解释来看 一个词的边界就是一个词不被另外一个“字”字符跟随的位置
如果你认为空格就是边界词的话这是不完全正确的理解
const str = "Singh hand some";
这里有几个边界词呢 答案是6个
const str = "Singh hand some";
str.match(/\b/g)
(6) ['', '', '', '', '', '']
边界指的是就是位置,这6个位置分别是
没错,边界的理解就是一个\w的另一边不是\w,那么说明它在边界
反向引用 \N
在讲解反向引用怎么用之前,先来论述一下反向引用和位置的关系
反向引用是指当我们匹配到一个模式后开始,直到下一次匹配到该模式的之间内容(位置)
反向引用是开始和结束的匹配关系
让我们来看一个例子
const str = `I said "you can't have both"`;
这里我想要匹配的是由 双引号 " 开头 并且由 双引号 " 结尾区间的内容
或者是单引号 ’ 开头结尾之间的内容
const reg = /["'](.*?)["']/g;
这样匹配到的是 you can
因为这既可以是双引号也可以是单引号
为了保证开头模式和结尾模式相同,我们可以使用反向引用
const reg = /(["'])(.*?)\1/g;
这里的 \1 是分组的序号,可以是\1 \2 \3 …\N,根据分组规则选择你希望匹配的第几个分组既可,其核心目的在于引用之前的分组,划定一块相同模式区间的内容。
你也可以通过给捕获组具名的方式,具名反向引用,通过\k 表示
const reg = /(?<yname>["'])(.*?)\k<yname>/g;
4、前瞻断言与后瞻断言
有的时候我们需要将一个 “模式” 必须匹配在另一个"模式"之前或者之后的位置,这个时候可以使用前瞻后瞻断言。
前瞻断言:X(?=Y)
后瞻断言:(?<=Y)X
这里的X表着断言之前(之后)的模式,Y代表以及用于断言的模式,只有两个模式都匹配上了,才能通过正则。
前瞻断言
const str = "1 turkey costs 30%
"
这里我想匹配的是数字后面跟着%的数字
str.match(/\d+(?=%)/)
['30', index: 15, input: '1 turkey costs 30%', groups: undefined]
呼应一下上面说的 只有两个模式都匹配上了,才能通过正则。
这里的 X = \d+, Y = (?=$)
前瞻断言和后瞻断言括号中的内容不会成为结果的一部分,如果我们希望 % 也在结果中可以通过一个而外的括号来包裹
str.match(/\d+(?=(%))/)
['30', '%', index: 15, input: '1 turkey costs 30%', groups: undefined]
断言也分为肯定和否定
前瞻否定断言:X(?!Y)
后瞻否定断言:(?<!Y)X
比如上面这里数字后面不跟着 %
str.match(/\d+(?!%)/)
['1', index: 0, input: '1 turkey costs 30%', groups: undefined]
后瞻断言
后瞻和前瞻是一样的,只不过他在反方向上进行条件判断
const str = "1 turkey costs %30
"
这里我想匹配的是数字前面带有 % 的数字
str.match(/(?<=%)\d+/)
['30', index: 16, input: '1 turkey costs %30', groups: undefined]
// 后瞻否定写法
str.match(/(?<!=%)\d+/)
最后通过一个前瞻断言实现数字千分位来总结一下
/(\d)(?=(\d{3})+$)/g
这里我理解的是 正则表达式内建引擎一旦满足了匹配结果,就会忽略已经匹配的所有内容,并尝试跟多的匹配
str.match(/\d(?=(\d{3})+$)/g)
(3) ['1', '4', '7']
按照这个理论 第一个匹配到的是 7 然后忽视7及7之前的内容,然后到 4 再忽视~ 再到 1~
然而结果不是,希望有大佬能告知 [\dog]