正则表达式笔记

181 阅读1分钟

从头开始学习正则(内容简单)

基本概念

匹配 unicode 字符
\u00e9

^ 脱字符 匹配行或者字符串起始位置
$ 美元符
匹配字面值的点号,可以使用转义 \. 或者放入字符组中 [.]

  1. 量词
    ?:0个或一个,表示字符是可选的,相当于{0,1}
    +:一个或多个,相当于{1,}
    *:0个或多个,相当于{0,}
    {a}:待查找的字符出现的次数a次
    {a,}:待查找的字符至少出现的次数a次
    {a,b}:待查找的字符至少出现的次数a次,最多出现b次
  2. 字符组
    [a-z]:[]字符组起止符,中间是可选的字符
    [^\d]:字符数组取反,也就是不匹配里边这些内容,排除这些
  3. 简写式
    \d:数字,相当于[0-9]
    \w:单词字符,相当于[a-zA-Z0-9_]
    \s:空白字符,包括换行,相当于[\n\t\r ]
    \b:单词边界,零宽断言,不占用字符
  4. 元字符
    ^:锚位符,匹配行或者字符串起始位置
    $:锚位符,匹配行或者字符串结尾位置
    []:字符组首尾
    ():分组
    -:范围符
    \:转义符
    .:除了换行以外任意字符
    *+?:量词,见第一点
    |:或
    {}:范围
  5. 环视
    aaa (?=bbb):正前瞻
    aaa (?!bbb):反前瞻
    (?<=aaa) bbb:正后顾
    (?<!aaa) bbb:反后顾

捕获分组和向后引用

当一个模式的全部内容或者部分内容有一对括号分组时,他就对内容进行捕获并存储于内存中,可以通过后向引用重用捕获的内容,形式为 \1 或 $1

\1 引用第一个分组内容

非捕获分组
不会将内容存储到内存中,所以有较高性能
用法:(?:the|The|THE)

原子分组
也是一种非捕获分组,可以将回溯操作关闭
用法:(?>the|The|THE)

环视
也是一种非捕获分组

量词

前面一小节已简单介绍,这节详细介绍。

贪心 懒惰 占有

量词自身是贪心的,贪心的量词会尽可能匹配更多的字符串,如果失败,会回退一个字符再次尝试。这个过程叫做 回溯 。每次回退一个字符,直到匹配或者没有字符尝试了,并且记录所有的行为。

懒惰就是非贪婪模式,每次匹配一个字符,最后匹配整个字符串。使变成懒惰只需在普通量词后面加上?

占有,只尝试一次,不会回溯使,变成占有只需在普通量词后面加上+

.* : 任意字符出现0次或多次
.*? : 非贪婪模式,匹配任意少的字符
.*+ : 独占模式,尽可能匹配,但不回溯;也就是已匹配的字符不会返还

环视

是一种非捕获分组,他根据某个模式之前或之后的内容匹配其他模式;也是零宽度断言

环视包括:
aaa (?=bbb):正前瞻
aaa (?!bbb):反前瞻
(?<=aaa) bbb:正后顾
(?<!aaa) bbb:反后顾

正前瞻

假设要匹配aaa,且紧跟其后的是bbb,这时可用正前瞻,表达式如下:
aaa (?=bbb)
因为是零宽断言,所以结果没有bbb

反前瞻

就是对正前瞻取反,要匹配aaa,且紧跟其后的不是bbb,表达式如下:
aaa (?!bbb)
仅仅把=改成!,其他不变

正后顾

正后顾会查看左边的内容,与正前瞻也是相对的;表达式如下:
(?<=aaa) bbb
与正前瞻相比,多了<,表明后顾的方向

反后顾

对正后顾取反,表达式如下:
(?<!aaa) bbb

正则示例

a+ 匹配1个或更多的a
(ab)+ 匹配1个或更多个ab
(ab | ac) ab 或 ac都可以 提取公共 a(b | c)

正则匹配过程

首先从正则表达式读取一个字符,再从字符串中取一个字符,比较,如果匹配,再获取正则下一个字符和字符串下一个字符比较,直至匹配或者没有字符了;
如果不匹配,获取字符串下一个字符继续比较。

如果是贪心的量词,会尽可能多的匹配,如果下一个正则字符匹配不上,会往前回退一个字符,重新匹配,直到匹配或没有字符。如果回溯步数太多,会导致匹配时间过长,长时间占用cpu 也就是 灾难性回溯

推荐几个网址,可在线验证测试正则,还可debug。

regex101
regexr

regex.png

regex101.png

分析几个正则

^([ ]?[\w]{1,60})+$

  • ^ 判断一行或字符串开头的零宽断言
  • ( 捕获分组的左括号
  • [ ]? 包含可选空格的字符组
  • [\w]{1,60} 1-60位的单词字符
  • ) 捕获分组的右括号
  • + 1个或更多字符
  • $ 判断一行或字符串结尾的零宽断言

(?=\B(\d{3})+$)

  • (?= 正前瞻分组,这里匹配边界
  • \B 非单词边界,这里把头尾的边界去了
  • (\d{3})+ 一个或更多的3位数字
  • $ 判断一行或字符串结尾的零宽断言
  • ) 分组的有括号

参考文献

  1. 学习正则表达式-[美]Micbael Fitzgerald