# 正则表达式

参考

- [php.net PCRE 正则语法](https://www.php.net/manual/zh/regexp.reference.meta.php)
- [runoob.com 正则表达式](https://www.runoob.com/regexp/regexp-syntax.html)

## 元字符

正则表达式的威力源于它可以在模式中拥有选择和重复的能力。 一些字符被赋予 特殊的涵义，使其不再单纯的代表自己，模式中的这种有特殊涵义的编码字符 称为 元字符。

共有两种不同的元字符：一种是可以在模式中方括号外任何地方使用的，另外一种 是需要在方括号内使用的。 在方括号外使用的元字符如下：

**方括号外的元字符**

元字符 | 描述
-----|-----
`\` | 一般用于转义字符
`^` | 断言目标的开始位置(或在多行模式下是行首)
`$` | 断言目标的结束位置(或在多行模式下是行尾)
`.` | 匹配除换行符外的任何字符(默认)
`[` | 开始字符类定义
`]` | 结束字符类定义
`|` | 开始一个可选分支
`(` | 子组的开始标记
`)` | 子组的结束标记
`?` | 作为量词，表示 0 次或 1 次匹配。位于量词后面用于改变量词的贪婪特性。 (查阅量词)
`*` | 量词，0 次或多次匹配
`+` | 量词，1 次或多次匹配
`{` | 自定义量词开始标记
`}` | 自定义量词结束标记

模式中方括号内的部分称为“字符类”。 在一个字符类中仅有以下可用元字符：

**方括号内的元字符（字符类）**

元字符 | 描述
-----|-----
\ | 转义字符
^ | 仅在作为第一个字符(方括号内)时，表明字符类取反
- | 标记字符范围

from: [php.net PCRE 正则语法](https://www.php.net/manual/zh/regexp.reference.meta.php)

## 转义序列(反斜线)

**用来描述特定的字符类**

字符  | 含义
-----|-----
`\d` | 任意十进制数字
`\D` | 任意非十进制数字
`\h` | 任意水平空白字符
`\H` | 任意非水平空白字符
`\s` | 任意空白字符
`\S` | 任意非空白字符
`\v` | 任意垂直空白字符
`\V` | 任意非垂直空白字符
`\w` | 任意单词字符
`\W` | 任意非单词字符

上面每一对转义序列都代表了完整字符集中两个不相交的部分， 任意字符一定会匹配其中一个，同时一定不会匹配另外一个

- "空白字符"（whitespace）是 HT (9)、LF (10)、FF (12)、CR (13)、space (32)。
- 单词字符指的是任意字母、数字、下划线

## 非打印字符

非打印字符也可以是正则表达式的组成部分。下表列出了表示非打印字符的转义序列：

字符 | 描述
----|-------
`\cx` | 匹配由x指明的控制字符。例如， `\cM` 匹配一个 `Control-M` 或回车符。`x` 的值必须为 `A-Z` 或 `a-z` 之一。否则，将 `c` 视为一个原义的 'c' 字符。
`\f` | 匹配一个换页符。等价于 `\x0c` 和 `\cL`。
`\n` | 匹配一个换行符。等价于 `\x0a` 和 `\cJ`。
`\r` | 匹配一个回车符。等价于 `\x0d` 和 `\cM`。
`\s` | 匹配任何空白字符，包括空格、制表符、换页符等等。等价于 `[ \f\n\r\t\v]`。注意 Unicode 正则表达式会匹配全角空格符。
`\S` | 匹配任何非空白字符。等价于 `[^ \f\n\r\t\v]`。
`\t` | 匹配一个制表符。等价于 `\x09` 和 `\cI`。
`\v` | 匹配一个垂直制表符。等价于 `\x0b` 和 `\cK`。

## 限定符 重复/量词

重复次数是通过量词指定的，可以紧跟在下面元素之后：

- 单独的字符, 可以是经过转义的
- 元字符。
- 字符类
- 后向引用(参加下一部分)
- 子组(除非它是一个断言，参考下文)

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。

正则表达式的限定符有：

字符	| 描述
-----|------
`*` |  匹配前面的子表达式零次或多次。例如，`zo*` 能匹配 "z" 以及 "zoo"。`*` 等价于{0,}。
`+` | 匹配前面的子表达式一次或多次。例如，'zo+' 能匹配 "zo" 以及 "zoo"，但不能匹配 "z"。`+` 等价于 {1,}。
`?` | 匹配前面的子表达式零次或一次。例如，"do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 、 "doxy" 中的 "do" 。`?` 等价于 {0,1}。
`{n}` | n 是一个非负整数。匹配确定的 n 次。例如，'o{2}' 不能匹配 "Bob" 中的 'o'，但是能匹配 "food" 中的两个 o。
`{n,}` | n 是一个非负整数。至少匹配n 次。例如，'o{2,}' 不能匹配 "Bob" 中的 'o'，但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
`{n,m}` | m 和 n 均为非负整数，其中n <= m。最少匹配 n 次且最多匹配 m 次。例如，"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

## 模式修饰符

下面列出了当前可用的 PCRE 修饰符。括号中提到的名字是 PCRE 内部这些修饰符的名称。 

> 模式修饰符中的空格，换行符会被忽略，其他字符会导致错误。

- `i (PCRE_CASELESS)`  如果设置了这个修饰符，`模式中的字母会进行大小写不敏感匹配`
- `m (PCRE_MULTILINE)`  默认情况下，PCRE 认为目标字符串是由单行字符组成的(然而实际上它可能会包含多行)，
"行首"元字符 (`^`) 仅匹配字符串的开始位置， 而"行末"元字符 (`$`) 仅匹配字符串末尾，或者最后的换行符(除非设置了 `D` 修饰符)。
这个行为和 perl 相同。 当这个修饰符设置之后，“行首”和“行末”就会匹配目标字符串中任意换行符之前或之后，另外， 还分别匹配目标字符串的最开始和最末尾位置。
这等同于 perl 的 `/m` 修饰符。如果目标字符串 中没有 `\n` 字符，或者模式中没有出现 `^` 或 `$`，设置这个修饰符不产生任何影响。
- `s (PCRE_DOTALL)` 如果设置了这个修饰符，模式中的点号元字符匹配所有字符，包含换行符。如果没有这个 修饰符，点号不匹配换行符。
这个修饰符等同于 perl 中的 `/s` 修饰符。 一个取反字符类比如 `[^a]` 总是匹配换行符，而不依赖于这个修饰符的设置。
- `x (PCRE_EXTENDED)` 如果设置了这个修饰符，模式中的没有经过转义的或不在字符类中的空白数据字符总会被忽略， 并且位于一个未转义的字符类外部的#字符和下一个换行符之间的字符也被忽略。
这个修饰符 等同于 perl 中的 `/x` 修饰符，使被编译模式中可以包含注释。 注意：这仅用于数据字符。 
空白字符 还是不能在模式的特殊字符序列中出现，比如序列 `(?(` 引入了一个条件子组(译注: 这种语法定义的 特殊字符序列中如果出现空白字符会导致编译错误。 比如 `(?(`就会导致错误)。
- `A (PCRE_ANCHORED)` 如果设置了这个修饰符，模式被强制为"锚定"模式，也就是说约束匹配使其仅从 **目标字符串的开始位置搜索**。
这个效果同样可以使用适当的模式构造出来，并且 这也是 perl 种实现这种模式的唯一途径。
- `D (PCRE_DOLLAR_ENDONLY)` 如果这个修饰符被设置，模式中的元字符美元符号仅仅匹配目标字符串的末尾。
如果这个修饰符 没有设置，当字符串以一个换行符结尾时， `$` 还会匹配该换行符(但不会匹配之前的任何换行符)。 
如果设置了修饰符`m`，这个修饰符被忽略. 在 perl 中没有与此修饰符等同的修饰符。
- `S` 当一个模式需要多次使用的时候，为了得到匹配速度的提升，值得花费一些时间 对其进行一些额外的分析。
如果设置了这个修饰符，这个额外的分析就会执行。当前，这种对一个模式的分析 _仅仅适用于非锚定模式的匹配(即没有单独的固定开始字符)_。
- `U (PCRE_UNGREEDY)` 这个修饰符逆转了量词的"贪婪"模式。 使量词默认为非贪婪的，通过量词后紧跟 `?` 的方式可以使其成为贪婪的。
这和 perl 是不兼容的。 它同样可以使用 模式内修饰符设置 `(?U)` 进行设置， 或者在量词后以问号标记其非贪婪(比如 `.*?`)
- `X (PCRE_EXTRA)` 这个修饰符打开了 PCRE 与 perl 不兼容的附件功能。模式中的任意反斜线后就 `ingen` 一个 没有特殊含义的字符都会导致一个错误，以此保留这些字符以保证向后兼容性。
默认情况下，在 perl 中，反斜线紧跟一个没有特殊含义的字符被认为是该字符的原文。 当前没有其他特性由这个修饰符控制。
- `J (PCRE_INFO_JCHANGED)` 内部选项设置 `(?J)` 修改本地的 `PCRE_DUPNAMES` 选项。允许子组重名，(译注：只能通过内部选项设置，外部的 `/J` 设置会产生错误。) 自 PHP 7.2.0 起，也能支持 `J` 修饰符。
- `u (PCRE_UTF8)` 此修正符打开一个与 Perl 不兼容的附加功能。 
模式和目标字符串都被认为是 UTF-8 的。 无效的目标字符串会导致 `preg_*` 函数什么都匹配不到；
无效的模式字符串会导致 E_WARNING 级别的错误。 5 字节和 6 字节的 UTF-8 字符序列以无效字符序列对待

