[正则] 正则匹配语法和应用流程

正则匹配语法

文章目录

  • 正则匹配语法
    • 1 字符匹配
      • 一对一
      • 一对多
    • 2 间隙匹配
    • 3 匹配重复
      • 重复量词
      • 贪婪与惰性匹配
      • 回溯与不回溯匹配
    • 4 匹配分支
    • 5 分组
    • 6 分组引用
      • 匹配时
        • 外部引用
        • 内部引用(递归)
      • 替换时
    • 7 优先级
    • 8 应用流程
      • 匹配
      • 搜索
      • 替换

匹配一词的使用可能存在主宾语反置的争议, 本文按: 正则式 匹配 字符串 的语法使用该词.
正则表达式中各类术语的译名和命名花样百出, 学习正则表达式时还需摸透本质, 不要纠结于命名.

1 字符匹配

这里按匹配映射的性质划分正则表达式的表达单元, 也有按元字符划分的文章

一对一

表达式 单一字符
a b c a b c等(默认, 可配置为忽略大小写)
\r <回车> (r=return)
\n <换行> (n=newline)
\t <制表符> (t=tab)
\\ \
\( (
\) )
\. .
\+ +
\* *
\- -

一对多

表达式 字符集合
. 换行符以外的字符(默认)([^\r\n])或一切字符(单行模式)([^])
\w 组词字符([a-zA-Z0-9_])
\W 非组词字符([^\w])
\s 空白字符([\t ])
\S 非空白字符([^\s])
\d 数字字符([0-9])
\D 非数字字符([^\d])
[exp] exp中任一字符, 限字符匹配中所用的表达式(方括号表达式除外)
[^exp] exp之外任意字符, 限字符匹配中所用的表达式(方括号表达式除外)
[c-d] 字符c和字符d及字符c到字符d之间的任意字符(字符按ASCII或UNICODE排序)
[exp1&&[exp2]] [exp1]和[exp2]的交集(java等)
[[::name::]] 特定的字符集合(php等)

在表达式前添加 (?i) 可使其后并连的所有表达式匹配时忽略大小写如 ((?i)ab)c 匹配 abc Abc ABc ABc

非法的正则式: [a-b-z]
部分非法, 部分合法的正则式: [^](若合法, 则指一切字符)
[(a-z)(0-9)]等价于[a-z0-9()]
[^^]等价于\^
[^-z]等价于[^z-]

注意: 括号中参考的等价正则式未必是具体实现, 仅供参考, 例如\s可能还能匹配全角空格, \d可能还匹配罗马数字等, 部分正则式引擎可能不支持\w \s等. 不支持交集的正则式引擎处理嵌套的未转义的方括号时可能有bug.

2 间隙匹配

间隙匹配又称作环视, 断言, 正/反向匹配, 预搜索, 条件匹配等.

表达式 间隙的描述
^ 行首(多行模式)((?<=[\r\n]+))或仅全文首
$ 行尾(多行模式)((?=[\r\n]+))或仅全文尾
\b 词际((?:(?<=\W)(?=\w)|(?<=\w)(?=\W)))
(?=exp) 尾随exp, 匹配exp前的间隙
(?!exp) 非尾随exp, 匹配非exp前的一切间隙
(?<=exp) 前导exp, 匹配exp后的间隙
(? 非前导exp, 匹配非exp后的一切间隙

^$ 并无默认匹配, 不同引擎有不同的默认模式.
注意: ^, $, \b的描述中的括号仅供简单参考, ^还能匹配全文的开头, $还能匹配全文的结尾, \b满足条件时亦同. 另外, 依正则式引擎的不同, 对其内exp有不同的限制.

3 匹配重复

表达式后可依次紧接重复量词, 惰性标志 ?, 不回溯标志 +
?+可叠用, 但?需在前, 正确的表达式如.??+, .+?+, 非法的表达式如 .*?+

重复量词

表达式 间隔的描述
? {0,1} 0或1次
+ {1,} 1次以上
* {0,} 任意次
{n} 恰n次
{n,} n次以上
{n,m} n到m次

注意: 不要写诸如 (.*)* 的表达式, 而是化简为 .*, 因为前者远比后者慢

贪婪与惰性匹配

默认为贪婪匹配, 即当匹配n到m次均可时, 则匹配m次
表达式后添惰性标志?, 可更改为惰性匹配, 即匹配n到m次均可时, 则匹配n次

回溯与不回溯匹配

默认为回溯匹配, 即匹配n到m次均可时, 则匹配n或m次
但当匹配n或m次导致后面的表达式无法匹配时, 将改为匹配n+1或m-1次, 重试后面的匹配(即回溯), 以此类推

表达式后添不回溯标志+, 可更改为不回溯匹配, 又称占有优先匹配, 即匹配n到m次均可时, 则只匹配m或n次
当匹配导致后面的表达式无法匹配时, 不更改匹配次数(即不回溯), 直接按匹配失败处理

当需要令多个匹配重复不回溯时, 使用固化分组 (?>exp).
固化分组又称独立表达式, 是不回溯标志的扩展, 逻辑上约等于 (?=(exp))\1.

非固化分组首次按贪婪/惰性方式匹配字符串, 导致后方字符串匹配失败时, 该非固化分组将改变内部的贪婪/惰性的匹配次数, 重试后方的匹配(即回溯), 直到后面表达式能匹配成功或遍历了所有的匹配次数都使得后方表达式无法匹配而最终整个表达式匹配失败.

固化分组直接按其贪婪/惰性方式匹配字符串, 其匹配结果导致后方字符串无法匹配时, 整个固化分组表达式直接匹配失败, 不重试. 可利用该不回溯匹配的特性可优化正则式的匹配速度.

注意: 并非所有正则式引擎都支持不回溯匹配

4 匹配分支

  • 或分支: |
  • 条件分支: (?(?=exp)true-exp) 等价于 (?:(?=exp)true-exp)
  • 条件分支: (?(?=exp)true-exp|false-exp) 等价于 (?:(?=exp)true-exp|false-exp)

或分支首先按左侧的表达式匹配, 无法匹配或导致后方表达式无法匹配时则尝试右侧表达式(即存在回溯).
条件分支中含多个 | 时, 取左起不在括号内的第一个|true-expfalse-exp 的划分.

5 分组

捕获分组:

  • 编号分组: (exp)
  • 命名分组: (?exp)

捕获分组(编号分组和命名分组)均参与编号, 从左到右以左括号出现次序的先后从1开始编号, 该编号是为了能在下文分组引用中被引用而设立, 分组匹配的内容取最后一次匹配到的内容
例: (a(b)+c+)(?d)编号为((1号)a((2号)b)+c+)((3号)?d)
预留的0号分组特指整个被匹配的字符串

非捕获分组:

  • 匿名分组: (?:exp)
  • 注释分组: (?#comment)
  • 其他一切分组

6 分组引用

匹配时

外部引用

又称反向引用

  • 引用编号分组: \n \nn \nnn
  • 引用命名分组: \g \k \k'name'

其中的 n nn nnn 是分组编号,
不同的正则式引擎可能有不同的语法, 此处列出多个供参考, 下同

内部引用(递归)

  • 引用所在分组: (?R)
  • 引用编号分组: (?n) (?Rn)
  • 引用命名分组: (?R) (?R'name')

替换时

以下表达式只用在替换式中

  • 引用当前匹配结果: $0 $&
  • 引用当前匹配结果中的编号分组: $n $nn $nnn
  • 引用当前匹配结果中的命名分组: ${name}
  • 引用当前匹配结果中最后一个分组: $+
  • 引用当前匹配结果在原字符串之后的所有字符: $'
  • 引用当前匹配结果在原字符串之前的所有字符: $`

有些正则式引擎在替换时亦可使用匹配时的\n \nn \nnn取代替换时的$n $nn $nnn.

7 优先级

下面按优先级最先和最后的顺序列出各个符号的优先级

  • \ 转义符
  • () []
  • ? + * {}
  • ab 并连, ^ $
  • |

优先级并无明文定义, 只是根据语法定义导出的方便人们理解语法的概念

8 应用流程

正则式一般有三种用途, 匹配, 搜索和替换, 它们的功能是渐进的关系.
下文的匹配配置有些在接口处输入, 有些附加在正则式后(如javascript).

此处列出ECMAScript下, 附加在正则式后的修饰符的作用, 也为上文中的一些非默认模式作说明

修饰符 名称 作用
g 全局模式 全部搜索/替换
i 匹配字母时忽略大小写
m 多行模式 ^$ 匹配换行符前后的间隙
y 粘性搜索, 手动接续搜索/替换
u 以UTF-16编码识别字符串
s 单行模式 . 也匹配换行符, 即匹配一切字符

匹配

匹配需要三项数据: 正则式 字符串 匹配配置(可选)
结果为布尔值
例: \w+@\w+\.com匹配[email protected], 结果: 成功
\w+@\w+\.com匹配[email protected], 结果: 失败

搜索

搜索需要三项数据: 正则式 字符串 匹配配置(可选)
结果为零个或多个匹配结果对象
例: \w+@\w+\.com搜索[email protected] [email protected], 第一个结果: [email protected](0号), 第二个结果: [email protected](0号)
(\w+)@(\w+)\.com搜索[email protected] [email protected], 第一个结果: [email protected](0号) a(1号) b(2号), 第二个结果: [email protected](0号) c(1号) d(2号)

有些正则式引擎不提供一次搜索出所有结果的接口, 只提供单次搜索的结果, 此时要求开发者自行编写循环, 遍历出所有结果. 一般每个结果都含匹配到的字符串的最后一个字符在原字符串里的下一个字符的索引.

替换

替换需要四项数据: 正则式 替换式 字符串 匹配配置(可选)
结果为替换后的字符串
例: (\w+)@(\w+)\.com替换[email protected] [email protected]$2@$1.cn, 得到[email protected] [email protected]

替换式不是正则式, 替换式只使用替换时引用分组的表达式.

例1: " It's a\n nice day. "(不含前后的引号, 此处引号只为突显前后的空格)
\b匹配: " ^It^'^s^ ^a^\n ^nice^ ^day^. " (^插入处的间隙)
^匹配: "^ It's a\n^ nice day. " (^插入处的间隙)
$匹配: " It's a^\n nice day. ^" (^插入处的间隙)

例2: \w+匹配abc, 第一次匹配的结果是abc(0号)
\w+?匹配abc, 第一次匹配的结果是a(0号)

例3: a(\w)+d匹配abcd, 第一次匹配的结果中, 1号分组匹配到c, 即abcd(0号), c(1号)

例4: ((?:\((?R)\)|{(?R)}|\[(?R)\]|\S)+)匹配[((hello){world})!]

例5: \d+匹配整数

例6: (?:\d+\.\d*|\.\d+)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+匹配浮点数

例7: ^\w+$匹配独占整行的单词, \b\\w+b匹配每一个单词

你可能感兴趣的:(正则表达式,regex)