正则表达式

元字符

字符 含义
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符
^ 匹配行首位置
$ 匹配行尾位置
\b 匹配一个单词边界,也就是指单词和空格间的位置
\B 匹配非单词边界
\d 匹配一个数字字符。等价于 [0-9]
\D 匹配一个非数字字符。等价于 [^0-9]。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]
\w 匹配字母、数字、下划线。等价于[A-Za-z0-9_]
\W 匹配非字母、数字、下划线。等价于[^A-Za-z0-9_]
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,\x41 匹配 "A"。\x041则等价于 \x04 & 1。正则表达式中可以使用 ASCII 编码。
\cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Za-z 之一。否则,将 c 视为一个原义的 c字符。
\f 匹配一个换页符。等价于 \x0c\cL
\r 匹配一个回车符。等价于 \x0d\cM
\n 匹配一个换行符。等价于 \x0a\cJ
\t 匹配一个制表符。等价于 \x09\cI
\v 匹配一个垂直制表符。等价于 \x0b\cK

限定符

限定符用于限定表达式匹配内容的出现次数

限定符 含义
expr* expr所匹配的内容可以出现零次或多次
expr+ expr所匹配内容可以出现一次或多次
expr? expr所匹配的内容可以出现零次或一次
expr{n} expr所匹配的内容只能出现n次
expr{n,} expr所匹配的内容至少出现n次
expr{n,m} expr所匹配的内容至少出现n次,至多出现m次

注意:

expr*expr+形式的限定符默认采用贪婪模式,如果采用非贪婪模式,则使用expr*?expr+?即可。

贪婪与非贪婪

贪婪匹配:正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。

非贪婪匹配:就是匹配到结果就好,就少的匹配字符。

如: 对于文本内容: abcaxc

如使用ab.*c匹配文本内容,结果就是匹配到:abcaxc整个字符串。

如使用ab.*?c匹配字符串文本内容,结果就是匹配到:abc

分组

将表达式做成一个单元,方便对表达式匹配的内容进行捕获

分组类型

捕获分组
格式 含义
expr expr为表达式内容,没有组名,只能通过该分组在整个正则中的分组顺序获取其匹配的内容
(?expr) 通过groupname指定分组名称,可以通过组名或者顺序获取匹配内容
非捕获分组
格式 含义
(?:expr) ?:在表达式之前,表示该分组只做匹配,不捕获其内容,例如:industr(?:y|lies) 会匹配industry或industries,但只捕获industr
零宽(断言|预查)
格式 含义
(?=expr) 零宽度正向肯定预查, 英文:look ahead positive assert 仅当子表达式 expr在 此位置的右侧匹配时才继续匹配 例如,Windows(?=95|98|NT|2000)能匹配windows2000中的windows,但是不能匹配windows7中的windows
(?!expr) 零宽度正向否定预查,英文:look ahead negative assert 仅当子表达式 expr不在此位置的右侧匹配时才继续匹配 例如,Windows(?!95|98|NT|2000)不能匹配windows2000中的windows,但是能匹配windows7windows10中的windows,也能匹配windows中的windows
(?<=expr) 零宽度负向肯定预查,look behind positive assert 仅当子表达式 expr在此位置的左侧匹配时才继续匹配 例如,(?<=95|98|NT|2000)Windows能匹配2000windows中的windows,但是不能匹配7windows中的windows
(?<!expr) 零宽度负向否定预查,look behind negative assert 仅当子表达式 expr不在此位置的左侧匹配时才继续匹配 例如,(?<!95|98|NT|2000)windows不能匹配2000windows中的windows,但是能匹配7windows10windows中的windows,也能匹配windows中的windows

预查不消耗字符:也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

分组的使用

分组的次序

在表达式 (expr1)(expr2(expr3))中,存在四个这样的组:

0 (expr1)(expr2(expr3))
1 (expr1)
2 (expr2(expr3))
3 (expr3)

第0组始终是整个表达式本身,分组有嵌套的话,先从外部分组开始计。

反向引用

一个分组所匹配的内容是可以被其他分组引用的。就拿匹配<title>.*</title>标签来说,就可以写成<(title)>.*</\1>

其中\1,就是对(title)分组的引用,1表示(title)在表达式中的次序。

注意:反向引用的作用是引用分组所匹配的内容,而不是分组所代表的正则表达式本身。例如:如果我们需要匹配一个IP地址,可以使用\d{1,3}(.\d{1,3}){3}这个正则,我们会发现\d{1,3}片段出现了两次,有人可能会觉得可以使用反向引用进行简化:(\d{1,3})(.\1){3}。但是这个表达式是不正确的,它只能匹配123.123.123.123192.192.192.192这类四个段都为一个数字的IP地址,而不能匹配192.168.119.91这样的IP地址。可以看出反向引用是引用分组所匹配的内容,而不是分组所代表的正则表达式本身。

侵占模式

匹配成功不进行回溯,与侵占量词“+”可以通用,比如:\d++ 可以写为 (?>\d+)

举例侵占模式:

将一些多位的小数截短到三位小数:`\d+\.\d\d[1-9]?\d+`。在这种条件下 `6.625` 能进行匹配,这样做没有必要,因为它本身就是三位小数。最后一个`5`本来是给 `[1-9]` 匹配的,但是后面还有一个 `\d+` 所以,`[1-9]` 由于是`?`可以不匹配所以只能放弃当前的匹配,将这个`5`送给 `\d+` 去匹配,如果改为:`\d+\.\d\d[1-9]?+\d+`的侵占形式,在`5`匹配到 `[1-9]` 时,由于是侵占式的,所以不会进行回溯,后面的 `\d+` 就匹配不到任东西了,所以导致 `6.625` 匹配失败。

这种情况,在替换时就有效了,比如把数字截短到小数点后三位,如果正好是三位小数的,就可以不用替换了,可以提高效率,侵占量词基本上就是用来提高匹配效率的。把 `\d+\.\d\d[1-9]?+\d+` 改为 `\d+\.\d\d(?>[1-9]?)\d+` 这样是一样的。
posted @ 2023-01-31 13:22  小张同学哈  阅读(19)  评论(0)    收藏  举报