# PCRE2高级语法参考手册
## 1. 反向引用(Backreferences)
反向引用允许在正则表达式中引用前面捕获组所匹配的内容。
### 1.1 数字反向引用
- `\1`, `\g1`, `\g{1}` - 引用第1个捕获组
- `\2`, `\g2`, `\g{2}` - 引用第2个捕获组
- `\3`, `\g3`, `\g{3}` - 引用第3个捕获组
**示例:**
- 文本: "abcabc"
- 表达式: `(abc)\1`
- 预期结果: 匹配整个字符串"abcabc"
- 文本: "hello world hello"
- 表达式: `(\w+)\s+\w+\s+(\1)`
- 预期结果: 匹配整个字符串,第二个捕获组捕获"hello"
### 1.2 相对反向引用
- `\g{-1}`, `\g{-2}`... - 相对于当前位置向前数的捕获组
- `\g{+1}`, `\g{+2}`... - 相对于当前位置向后数的捕获组
**示例:**
- 文本: "xyxy"
- 表达式: `(x)(y)\g{-2}\g{-1}`
- 预期结果: 匹配整个字符串"xyxy"
### 1.3 命名反向引用
- `\k<name>` - Perl风格的命名反向引用
- `\k'name'` - 单引号语法
- `\g{name}` - 通用命名引用语法
- `(?P=name)` - Python风格语法
**示例:**
- 文本: "hello world hello"
- 表达式: `(?<word>\w+)\s+\w+\s+(\k<word>)`
- 预期结果: 匹配整个字符串,第二个捕获组捕获"hello"
## 2. 递归表达式(Recursive Expressions)
递归表达式允许正则表达式匹配嵌套或递归的结构。
### 2.1 整体模式递归
- `(?R)` - 递归整个正则表达式模式
- `(?0)` - 与`(?R)`相同,递归整个模式
**示例:**
- 文本: "(a(b(c)d)e)"
- 表达式: `\(([^()]++|(?R))*\)`
- 预期结果: 匹配整个字符串"(a(b(c)d)e)"
### 2.2 捕获组递归
- `(?1)`, `(?2)`, `(?n)` - 递归引用第1、2、n个捕获组
- `(?+n)` - 相对递归,向后数第n个捕获组
- `(?-n)` - 相对递归,向前数第n个捕获组
**示例:**
- 文本: "(a(b)c)"
- 表达式: `(\(([^()]++|(?1))*\))`
- 预期结果: 匹配整个字符串"(a(b)c)"
- 文本: "((()))"
- 表达式: `(\(([^()]++|(?1))*\))`
- 预期结果: 匹配整个字符串"((()))"
### 2.3 命名递归
- `(?&name)` - 递归名为name的捕获组(Perl语法)
- `(?P>name)` - Python风格语法
- `\g<name>` - Oniguruma风格语法
- `\g'name'` - Oniguruma单引号语法
**示例:**
- 文本: "(a(b)c)"
- 表达式: `(?<paren>\(([^()]++|(?&paren))*\))`
- 预期结果: 匹配整个字符串"(a(b)c)"
### 2.4 带返回值的递归(PCRE2扩展,TODO:尚未封装支持)
- `(?R(grouplist))` - 递归整个模式并返回指定捕获组
- `(?n(grouplist))` - 递归第n个组并返回指定捕获组
- `(?&name(grouplist))` - 递归命名组并返回指定捕获组
**示例:**
- 文本: "Saturday,Sat"
- 表达式: `(?x: # 忽略空格以便清晰
# 定义一个可重用的例程"weekendday",它匹配Saturday或
# Sunday,并返回Sat/Sun前缀作为\k<short>。
(?(DEFINE) (?<weekendday>
(?|(?<short>Sat)urday|(?<short>Sun)day) ) )
# 调用例程。匹配"Saturday,Sat"或"Sunday,Sun"。
(?&weekendday(<short>)),\k<short> )`
- 预期结果: 匹配整个字符串"Saturday,Sat",并返回命名捕获组short="Sat"
### 2.5 递归条件检测
- `(?(R)yes-pattern|no-pattern)` - 检查是否在递归中
- `(?(R1)yes-pattern|no-pattern)` - 检查是否在第1组的递归中
- `(?(R&name)yes-pattern|no-pattern)` - 检查是否在名为name的组的递归中
**示例:**
- 文本: "<div><span>text</span></div>"
- 表达式: `<(\w+)(?>(?:"[^"]*"|'[^']*'|[^>])*?)>(?:(?R)|[^<]*)</\1>`
- 预期结果: 匹配整个HTML标签结构
## 3. 原子分组(Atomic Groups)
原子分组阻止回溯进入分组内部。
### 3.1 语法
- `(?>...)` - 原子分组
- `(*atomic:...)` - Perl 5.28 引入的字母形式
### 3.2 示例
- 文本: "aardvark"
- 表达式: `(?>a*)a`
- 预期结果: 不匹配(原子分组消耗所有a,然后外面的a无法匹配)
- 文本: "abc123def"
- 表达式: `(?>[a-z]*)\d+`
- 预期结果: 匹配"abc123"(虽然只应匹配"123",但原子分组会消耗整个"abc")
批注:贪婪懒惰占有模式
1、Greedy 贪婪但回溯
* + ? {n,m}
尝试匹配尽量多的字符,但如果后面的正则无法匹配成功,它会吐出字符,尝试让后面的正则匹配
2、Lazy 懒惰
*? +? ?? {n,m}?
匹配尽可能少的字符,匹配后,如果后面的正则无法匹配成功,它会向前吃字符(回溯进食),尝试让后面的模式匹配成功
3、Possessive 霸道占有
尝试匹配尽量多的字符,且坚决不回吐
*+ ++ ?+ {n,m}+
## 4. 占有量词(Possessive Quantifiers)
占有量词表示贪婪匹配且不允许回溯。
### 4.1 语法
- `*+`, `++`, `?+`, `{n,m}+` - 在普通限定符后加`+`
### 4.2 示例
- 文本: "aaaaa"
- 表达式: `a++b`
- 预期结果: 不匹配(a++消耗所有a,没有剩余的给b)
- 文本: "aaaaa"
- 表达式: `a*a`
- 预期结果: 匹配"aaaaa"(普通限定符允许回溯)
## 5. 条件表达式(Conditional Groups)
根据条件选择不同的匹配分支。
### 5.1 捕获组条件
- `(?(1)yes-pattern|no-pattern)` - 如果第1个捕获组已匹配则使用yes-pattern
- `(?(<name>)yes-pattern|no-pattern)` - 如果名为name的捕获组已匹配则使用yes-pattern
**示例:**
- 文本: "(abc)123"
- 表达式: `(\()?abc(?(1)\)|123)`
- 预期结果: 匹配整个字符串"(abc)123"
- 文本: "abc123"
- 表达式: `(\()?abc(?(1)\)|123)`
- 预期结果: 匹配整个字符串"abc123"
### 5.2 递归条件
- `(?(R)yes-pattern|no-pattern)` - 如果正在递归则使用yes-pattern
- `(?(R1)yes-pattern|no-pattern)` - 如果正在递归第1个组则使用yes-pattern
### 5.3 断言条件
- `(?(?=assertion)yes-pattern|no-pattern)` - 前瞻断言为真时使用yes-pattern
- `(?(?!assertion)yes-pattern|no-pattern)` - 负前瞻断言为真时使用yes-pattern
**示例:**
- 文本: "password123"
- 表达式: `(?(?=\d)123|abc)`
- 预期结果: 不匹配(因为字符串以字母开头,不是数字)
- 文本: "123abc"
- 表达式: `(?(?=\d)123|abc)`
- 预期结果: 匹配"123"
## 6. 断言(Assertions)
断言用于测试某个条件是否满足,但不消耗字符。
### 6.1 前瞻断言
- `(?=...)` - 正向前瞻断言
- `(?!...)` - 负向前瞻断言
**示例:**
- 文本: "password123"
- 表达式: `\w+(?=123)`
- 预期结果: 匹配"password"(但不包括"123")
- 文本: "password456"
- 表达式: `\w+(?!123)`
- 预期结果: 匹配"password456"
### 6.2 后顾断言
- `(?<=...)` - 正向后顾断言(固定长度)
- `(?<!...)` - 负向后顾断言(固定长度)
**示例:**
- 文本: "price:100"
- 表达式: `(?<=:)\d+`
- 预期结果: 匹配"100"
- 文本: "amount200"
- 表达式: `(?<!:)\d+`
- 预期结果: 匹配"200"
### 6.3 非原子断言(PCRE2扩展)
- `(*napla:...)` 或 `(?*...)` - 非原子正向前瞻
- `(*naplb:...)` 或 `(?<*...)` - 非原子正向后顾
## 7. 子程序调用(Subroutine Calls)
将捕获组作为子程序调用。
### 7.1 语法
- `(?&name)` - 调用命名捕获组
- `(?n)` - 调用第n个捕获组
- `(?+n)`, `(?-n)` - 相对调用
- `(?P>name)` - Python语法
**示例:**
- 文本: "abc def ghi"
- 表达式: `(?<word>\w+)\s+(?&word)\s+\w+`
- 预期结果: 匹配"abc def ghi"(如果第二部分是"abc"的话)
## 8. 字符串扫描断言(PCRE2扩展)
检查捕获的子字符串是否符合特定模式。
### 8.1 语法
- `(*scan_substring:(group_numbers_or_names)...)` 或 `(*scs:(...)...)`
## 9. 脚本运行(Script Runs)
确保匹配的字符序列属于同一Unicode脚本。
### 9.1 语法
- `(*script_run:...)` 或 `(*sr:...)` - 确保匹配的字符是同一脚本运行
- `(*atomic_script_run:...)` 或 `(*asr:...)` - 原子脚本运行
## 10. 回溯控制动词(Backtracking Control Verbs)
控制匹配过程中的回溯行为。
### 10.1 立即动作动词
- `(*ACCEPT)` - 立即成功结束匹配
- `(*FAIL)` - 立即失败并触发回溯
**示例:**
- 文本: "abcdef"
- 表达式: `abc(*ACCEPT)xyz`
- 预期结果: 匹配"abc"
### 10.2 回溯后动作动词
- `(*COMMIT)` - 提交匹配点,失败时不尝试其他起始位置
- `(*PRUNE)` - 剪枝,失败时不再回溯到此点之前
- `(*SKIP)` - 跳过,失败时跳到此点位置继续匹配
- `(*THEN)` - 然后,失败时跳到下一个替代项
## 11. 标记(Mark)
记录匹配路径上的标记点。
### 11.1 语法
- `(*MARK:name)` 或 `(*:name)` - 设置标记名称
## 12. 特殊起始项(Special Start-of-Pattern Items)
在模式开头设置选项。
### 12.1 UTF支持
- `(*UTF)` - 启用UTF模式
### 12.2 Unicode属性支持
- `(*UCP)` - 使用Unicode属性进行\w、\d等匹配
### 12.3 行终止符约定
- `(*CR)` - 使用CR作为行终止符
- `(*LF)` - 使用LF作为行终止符
- `(*CRLF)` - 使用CRLF作为行终止符
- `(*ANYCRLF)` - 任何CR、LF或CRLF
- `(*ANY)` - 任何Unicode行终止符
- `(*NUL)` - 使用NUL字符作为行终止符
### 12.4 回溯限制
- `(*LIMIT_HEAP=d)` - 设置堆限制
- `(*LIMIT_MATCH=d)` - 设置匹配限制
- `(*LIMIT_DEPTH=d)` - 设置深度限制
## 13. 内部选项设置
在模式内部设置选项。
### 13.1 Perl兼容选项
- `(?i)` - 不区分大小写
- `(?m)` - 多行模式
- `(?s)` - 单行模式(点号匹配换行符)
- `(?x)` - 扩展模式(忽略空格)
- `(?xx)` - 扩展模式(额外忽略空格)
### 13.2 PCRE2特有选项
- `(?J)` - 允许重复的组名
- `(?U)` - 非贪婪默认
- `(?aD)` - ASCII \d
- `(?aS)` - ASCII \s
- `(?aW)` - ASCII \w
- `(?aP)` - ASCII POSIX类
## 14. 实际应用示例
### 14.1 反向引用示例
- 文本: "sensibility"
- 表达式: `(sens|respons)e and \1ibility`
- 预期结果: 不匹配(单独使用该表达式)
- 文本: "sense and sensibility"
- 表达式: `(sens|respons)e and \1ibility`
- 预期结果: 匹配整个字符串
### 14.2 递归表达式示例
- 文本: "((()))"
- 表达式: `\(([^()]++|(?R))*\)`
- 预期结果: 匹配整个字符串"((()))"
### 14.3 复杂模式示例
- 文本: "192.168.1.1"
- 表达式: `(?(DEFINE)(?<byte>2[0-4]\d|25[0-5]|1\d\d|[1-9]?\d))\b(?&byte)(\.(?&byte)){3}\b`
- 预期结果: 匹配整个IP地址
## 15. 注意事项
1. 反向引用必须引用已经存在的捕获组
2. 在重复组内的反向引用可以实现递归效果
3. 递归表达式可用于匹配任意深度的嵌套结构
4. 使用相对引用有助于编写可重用的正则表达式片段
5. 命名引用提高了正则表达式的可读性和维护性
6. 某些高级功能(如非固定长度后顾断言)在某些PCRE2版本中可能受限
7. 回溯控制动词仅在传统匹配函数中有效,不适用于DFA匹配
8. 某些功能可能需要特定的编译选项才能启用
9. 平衡组功能在我们的COM组件中通过语法转换实现,将.NET语法转换为PCRE2等价形式
这些功能使得PCRE2成为一个功能非常强大的正则表达式引擎,能够处理复杂的文本匹配任务。
Copyright © 2025- vba.vip All Rights Reserved.