正则表达式进阶
正则表达式,是每个程序员的必备的技能
贪婪匹配 和 惰性匹配
- 贪婪匹配是尽可能匹配更多的字符
- 惰性匹配是尽可能匹配更少的字符
惰性匹配是在 * , + , {m,} 后加上 ?
- *: 匹配前面 0 次或以上,尽可能多
- +: 匹配前面 1 次或以上,尽可能多
- {m,}: 匹配前面 m 次或以上,尽可能多
- *?: 匹配前面 0 次或以上,尽可能少
- +?: 匹配前面 1 次或以上,尽可能少
- {m,}?: 匹配前面 m 次或以上,尽可能少
举例
字符串
| 1 | 1a-2b-3c-4d-e5-f6 | 
除了 - 外,其他字符串都是不定长的,而且字符串也可以是其他除 - 外的字符甚至特殊符号
- 贪婪匹配- 表达式:^.+\-
- 匹配值:1a-2b-3c-4d-e5-
 
- 表达式:
- 惰性匹配- 表达式:^.+?\-
- 匹配值:1a-
 
- 表达式:
惰性匹配顺序问题
前面的例子,如果想匹配后面的 -f6,你可能会这样用
| 1 | \-.+?$ | 
但匹配结果是 -2b-3c-4d-e5-f6 而不是 -f6,和贪婪匹配结果一样
这是因为正则匹配是从前往后,当匹配到 -2 时发现匹配了一部分,就会继续向前查询 -2d > -2d- > -2d-3 > -2d-3c 等,直到查询 -2b-3c-4d-e5-f6 才找到满足条件的值
为了解决这个问题,可以用排除法,即排除前面的 -
| 1 | \-[^\-]+$ | 
字符串掐头去尾
在代码中,如果想去除字符串前面一部分,或者字符串后面一部分,可以用 正则 + 替换 的方式
文件名
| 1 | image.png | 
- 若只想要不带扩展名的名称,在 JS 中可以这样
| 1 | \..+$ | 
| 1 | const file = "image.png" | 
- 如果文件名中可能包含多个 .
| 1 | image.1.png | 
按上面的写法只能取到 image 而不是 image.1
这样做保留的文件名更完整
| 1 | \.+[^\.]*$ | 
| 1 | const file = "image.1.png" | 
- 如果只想保留扩展名,可以这样
| 1 | ^.*\. | 
| 1 | const file = "image.png" | 
环视
也称为零宽度断言,环视可以根据某个模式之前或之后的内容,要求匹配其他模式
正前瞻
匹配且要求紧随其后的内容为分组匹配的内容
| 1 | ?=分组 | 
如 [a-zA-Z](?=\d) ,若字母后是数字则匹配该字母 ,否则不匹配,即 [a-z] 后必须匹配 \d
反前瞻
对正前瞻含义取反,即匹配且要求紧随其后的内容不为分组匹配的内容
| 1 | ?!分组 | 
如 [a-zA-Z](?!\d) ,若字母后是数字则不匹配该字母 ,否则匹配,即 [a-z] 后必须不匹配 \d
正前顾
即对正前瞻方向取反,匹配且要求紧挨着之前的内容为分组匹配的内容
| 1 | ?<=分组 | 
如 (?<=\d)[a-zA-Z] ,若字母前是数字则匹配该字母 ,否则不匹配,即 [a-z] 前必须匹配 \d
反后顾
即对正前瞻方向取反,匹配且要求紧挨着之前的内容为分组匹配的内容
| 1 | ?<!分组 | 
如 (?<!\d)[a-zA-Z] ,若字母前是数字则不匹配该字母 ,否则匹配,即 [a-z] 前必须不匹配 \d
正向引用
子匹配可以被引用,使用 \n 访问
如 abcd<custom-button>link</custom-button>efg 匹配 custom-button 标签和其中的内容
| 1 | <(custom-button)>.*</\1> |