# 正则表达式

2024年5月13日9分钟阅读

- FormalSciences/ComputerScience
- GettingStarted/Other

## 概述

正则表达式（Regular Expression，Regex）是用于匹配字符串中字符组合的模式。它由一系列字符和特殊符号组成，可以高效地执行查找、替换、检查数据格式等多种文本处理任务。正则表达式的概念最初由数学家斯蒂芬·克莱尼在 20 世纪 50 年代提出，最早用于理论计算机科学和形式语言理论中。

几乎所有现代编程语言都支持正则表达式，包括 Python、JavaScript、Java、C#等。此外，许多文本编辑器和开发环境（如 VSCode、Sublime Text）以及命令行工具（如 grep）也广泛应用正则表达式进行文本搜索和编辑。

## 基本概念

- 字面字符：指在表达式中表示它们自身字面意义的字符，例如 `a`、`1`、`B`。
- 特殊字符：在正则表达式中用来表示控制或通配符作用的字符，如 `*`（匹配前一个字符 0 次或多次）。

### 元字符

元字符是构成正则表达式逻辑的基础，具有特殊的匹配含义：

元字符 | 描述
--- | ---
`.` | 句号匹配任意单个字符除了换行符。
`[ ]` | 字符种类。匹配方括号内的任意字符。
`[^ ]` | 否定的字符种类。匹配除了方括号里的任意字符
`*` | 匹配 >=0 个重复的在 * 号之前的字符。
`+` | 匹配 >=1 个重复的 + 号前的字符。
`?` | 标记 ? 之前的字符为可选。
`{n,m}` | 匹配 num 个大括号之前的字符或字符集 (n ⇐ num ⇐ m)。
`(xyz)` | 字符集，匹配与 xyz 完全相等的字符串。
` | `
`\` | 转义字符，用于匹配一些保留的字符 `[ ] ( ) { } . * + ? ^ $ \
`^` | 从开始行开始匹配。
`$` | 从末端开始匹配。

### 字符类

字符类允许匹配指定集合中的字符，常见的标准字符类和自定义字符类如下：

简写 | 描述
--- | ---
`.` | 除换行符外的所有字符
`\w` | 匹配所有字母数字，等同于 `[a-zA-Z0-9_]`
`\W` | 匹配所有非字母数字，即符号，等同于： `[^\w]`
`\d` | 匹配数字： `[0-9]`
`\D` | 匹配非数字： `[^\d]`
`\s` | 匹配所有空格字符，等同于： `[\t\n\f\r\p{Z}]`
`\S` | 匹配所有非空格字符： `[^\s]`
`\f` | 匹配一个换页符
`\n` | 匹配一个换行符
`\r` | 匹配一个回车符
`\t` | 匹配一个制表符
`\v` | 匹配一个垂直制表符
`\p` | 匹配 CR/LF（等同于 `\r\n`），用来匹配 DOS 行终止符

自定义字符类

示例 | 描述
--- | ---
`[a-z]` | 匹配任何小写字母
`[A-Z]` | 匹配任何大写字母
`[0-9]` | 匹配任何数字
`[aeiou]` | 匹配所有小写元音字母
`[^0-9]` | 匹配任何不是数字的字符（方括号内的 `^` 表示非）

### 位置匹配

位置匹配用于确定字符匹配的具体位置，如行首或行尾等：

锚点字符 | 描述
--- | ---
`^` | 不仅表示行的开始，也可在多行模式中匹配每一行的开始
`$` | 表示行的结束或字符串的结束，同样在多行模式中可匹配每一行的结束

## 量词和分组

量词和分组是正则表达式中非常强大的功能，它们让我们可以定义复杂的模式，进行精确的文本匹配和操作。这部分内容也可以用表格形式进行更清晰的展示。

### 量词

量词用于指定一个元素出现的次数，是正则表达式中控制匹配频度的关键工具。

量词 | 描述
--- | ---
`*` | 匹配前一个元素 0 次或多次。
`+` | 匹配前一个元素 1 次或多次。
`?` | 匹配前一个元素 0 次或 1 次。
`{n}` | 匹配前一个元素恰好 n 次。
`{n,}` | 匹配前一个元素至少 n 次。
`{n,m}` | 匹配前一个元素至少 n 次，但不超过 m 次。

#### 贪婪与非贪婪量词

量词默认为贪婪模式，尽可能多地匹配字符。通过添加 `?` 后缀，量词变为非贪婪模式，尽可能少地匹配字符。

类型 | 示例 | 描述
--- | --- | ---
贪婪匹配 | `a.*b` | 在 `axxxbxxxb` 中匹配从第一个 `a` 到最后一个 `b` 的整段文本。
非贪婪匹配 | `a.*?b` | 在 `axxxbxxxb` 中匹配最短的，以 `a` 开始，以 `b` 结束的文本。

### 分组和引用

分组允许将正则表达式中的部分模式括起来，作为一个整体进行操作，这对于提取信息、构建复杂模式或进行条件匹配非常有用。

#### 捕获分组与非捕获分组

类型 | 示例 | 描述
--- | --- | ---
捕获分组 | `(abc)` | 匹配 `abc`，并捕获匹配的文本，以供后续引用。
非捕获分组 | `(?:abc)` | 匹配 `abc`，但不捕获匹配的文本，仅用于匹配操作。

#### 后向引用

后向引用让我们能够引用正则表达式中先前定义的捕获组，这对于匹配重复的文本或验证两部分内容相同非常有用。

示例 | 描述
--- | ---
`(\b\w+)\s+\1` | 匹配一个由单词、空格和相同单词构成的模式，如 `word word`。

## 高级匹配

### 断言

断言是正则表达式中的一个高级特性，允许进行条件匹配，即只有在满足特定条件的情况下才进行匹配。

符号 | 描述
--- | ---
`?=` | 正先行断言 - 存在
`?!` | 负先行断言 - 排除
`?<=` | 正后发断言 - 存在
`?<!` | 负后发断言 - 排除

前向肯定断言 (`?=`)

- 前向肯定断言允许你指定一个子模式必须出现在某个匹配之后，但不会成为匹配结果的一部分。例如，`a(?=b)` 会匹配前面有 `a` 且后面紧跟 `b` 的位置，但不会返回 `b`。

前向否定断言 (`?!`)

- 前向否定断言用来指定一个子模式必须不出现在某个匹配之后。例如，`a(?!b)` 会匹配所有后面不跟 `b` 的 `a`。

后向断言

- 在支持的语言中（如 JavaScript），后向断言允许你指定一个子模式必须出现在某个匹配之前。如 `(?<=b)a` 表示 `a` 前面必须有 `b`。

### 标志/模式修饰符

标志或模式修饰符用于改变正则表达式的匹配行为。

标志 | 描述
--- | ---
`i` | 忽略大小写。
`g` | 全局搜索。
`m` | 多行修饰符：锚点元字符 `^` `$` 工作范围在每行的起始。

大小写不敏感 (`i`)

- 使用此标志后，匹配时将不区分大小写。例如，正则表达式 `/abc/i` 将匹配 `Abc`、`aBc`、`abc` 等。

多行模式 (`m`)

- 在多行模式下，`^` 和 `$` 不仅匹配输入字符串的开始和结束位置，也匹配行的开始和结束。

点号包含换行 (`s`)

- 通常，`.` 不匹配换行符。使用此标志后，`.` 也将匹配换行符。

## 参考实例

- regex101（正则表达式测试工具）
- REGEXP（正则表达式测试工具）
- Regulex（正则表达式可视化工具）
- any-rule（正则表达式大全）
- learn-regex