正则表达式进阶
正则表达式,是每个程序员的必备的技能
贪婪匹配 和 惰性匹配
- 贪婪匹配是尽可能匹配更多的字符
- 惰性匹配是尽可能匹配更少的字符
惰性匹配是在 *
, +
, {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> |