RegExp

AutoIt 正则表达式参考

字符串组成

对于字符串"a5", 是由两个字符 "a" 和 "5" 以及三个位置组成的(如下图所示), 这一点对于正则表达式的匹配原理理解很重要:

占有字符和零宽度

正则表达式匹配过程中, 如果子表达式匹配到的是字符内容, 而非位置, 并被保存到最终的匹配结果中, 则认为这个子表达式是占有字符的;
如果子表达式匹配的仅仅是位置, 或者匹配的内容并不保存到最终的匹配结果中, 则认为这个子表达式是零宽度的.

占有字符还是零宽度, 是针对匹配的内容是否保存到最终的匹配结果中而言的.

占有字符是互斥的, 零宽度是非互斥的. 也就是一个字符同一时间只能由一个子表达式匹配, 而一个位置却可以同时由多个零宽度的子表达式匹配.

正则表达式构成

正则表达式由两种字符构成. 一种是在正则表达式中具体特殊意义的"元字符", 另一种是普通的"文本字符".

元字符可以是一个字符, 如 ^ , 也可以是一个字符序列, 如 \w .

关于 AutoIt 正则表达式的一般说明

正则表达式表示法以紧凑方式搜索指定主题字符串，确定可以由 StringRegExp() 提取的匹配部分,
或可以由 StringRegExpReplace() 替换的匹配部分.

正则表达式引擎尝试匹配模式(一种编程格式)与对象的字符串, 并且按左到右的顺序执行搜索.
如果发生不匹配, 引擎尝试回溯(依次返回到以前的状态), 期待将匹配模式的其余部分.

AutoIt 使用 PCRE 引擎(Perl 兼容的正则表达式)，是最全面的开源引擎. 这个引擎包括 Unicode 类别属性(UCP)支持, 它允许大多数人类语言的细致处理.
然而, 为了维持与以前版本的兼容性, 并保持在其最佳的匹配速度, 默认不启用 UCP 支持.
您可以通过在表达式前添加字符串(*UCP)启用它. 启用时，UCP 设置将更改正则表达式的元素数目的扩展.

注意: 错误的正则表达式可以产生一个无限循环而占用 CPU, 甚至可以导致崩溃.

关于本文档的说明

网上关于正则表达式的教程, 参考......等等的文章不少, 相关示例也不少, 但都是基于某种编程语言书写! 详细分析正则表达式意义的却十分鲜见!

现实中也没有专为 AutoIt 语言的! AutoIt 帮助文档的这部分描述对于完全门外汉简直犹如天书!

这个参考以正则表达式示例分析为主, 没有诸如"什么是正则表达式"之类的东西! 资料收集于以下网页:

微软-正则表达式语言 - 快速参考(中文) 此文档主要收集于这个网页

下面两个网页为辅助参考收集

正则表达式基础(中文)

揭开正则表达式的神秘面纱(中文)

收集的正则表达式示例都是基于 C# 编程语言编写的, 本文档使用 afan 的 Au3.REHelper_正则助手[160128更新1.5.1] 调试修改为 AutoIt 语言格式! 在此致谢 afan !!!

本参考文档的描述文本兼顾 AutoIt 帮助的函数 StringRegExp() 文档页描述内容!

注意 : 此文档中参杂有我的理解, 这部分内容均已斜体字表示, 基于本人正则知识匮乏, 看客不可轻信 !!!

此文档中"匹配结果(标志 x)" 的 x 表示测试工具 Au3.REHelper_正则助手 的测试标志选项 0 至 4 !


正则表达式的工作方式

正则表达式提供了功能强大, 灵活而又高效的方法来处理文本. 正则表达式的全面模式匹配表示法使你可以快速分析大量文本以找到特定的字符模式:
验证文本以确保它匹配预定义的模式(如电子邮件地址);
提取, 编辑, 替换或删除文本子字符串;
将提取的字符串添加到集合以生成报告.

对于处理字符串或分析大文本块的许多应用程序而言, 正则表达式是不可缺少的工具.

使用正则表达式处理文本的中心构件是正则表达式引擎, 处理文本至少要求向该正则表达式引擎提供以下两方面的信息：
1. 提供正则表达式识别文本的模式. 正则表达式模式用特殊的语法或语言定义, 该语法或语言与 Perl 5 正则表达式兼容.
2. 提供正则表达式分析文本的模式.

正则表达式可以执行以下操作：
确定输入文本中是否具有匹配正则表达式模式的字符串
匹配正则表达式模式的一个或所有文本匹配项. 返回提供有关匹配文本的信息. 收集匹配对象.
通过调用 StringRegExpReplace() 替换匹配正则表达式模式的文本.

正则表达式示例

示例 1: 替换子字符串

假设一个邮件列表包含一些姓名, 这些姓名有时包括称谓(Mr., Mrs., Miss 或 Ms.) 以及姓氏和名字. 如果你从列表中生成信封标签时不希望包括称谓, 则可以使用正则表达式移除称谓, 如以下示例所示.

字符串: Mr. Henry Hunt, Ms. Sara Samuels, Abraham Adams, Ms. Nicole Norris

表达式: Mr\.? |Mrs\.? |Miss |Ms\.?

表达式模式可匹配任何 “Mr”, “Mr.”, “Mrs”, “Mrs.”, “Miss”, “Ms” 或 “Ms.”

从原始字符串中移除匹配项:

StringRegExpReplace("Mr. Henry Hunt, Ms. Sara Samuels, Abraham Adams, Ms. Nicole Norris", "Mr\.? |Mrs\.? |Miss |Ms\.?", "")

替换结果: Henry Hunt, Sara Samuels, Abraham Adams, Nicole Norris

示例 2: 标识重复的单词

意外地重复单词是编写器常犯的错误. 可以使用正则表达式标识重复的单词, 如以下示例所示.

字符串: This this is a nice day. What about this? This tastes good. I saw a a dog.

表达式: (?i)\b(\w+?)\s\1\b

匹配结果(标志 4):
[0]=> [0]This this
[0]=> [1]This ; 匹配开始位置 0
[1]=> [0]a a ; 匹配开始位置 66
[1]=> [1]a

表达式分析:

模式 | 说明
(?i) | 启动不区分大小写的匹配
\b | 在单词边界处开始
(\w+?) | 匹配一个或多个单词字符, 但字符要尽可能的少. 它们一起构成称为 \1 的捕获组
\s | 与空白字符匹配
\1 | 与等于名为 \1 捕获组的子字符串匹配
\b | 在单词边界处结束

此示例将子字符串“This this” , "a a" 标识为重复, 但如果子字符串 “this?This” 由于插入标点符号, 该子字符串不被标识为重复.

示例 3: 匹配货币符号

字符串:
Office expenses on 2/13/2008:
Paper (500 sheets) $3.95
Pencils (box of 10) $1.00
Pens (box of 10) $4.49
Erasers $2.19
Ink jet printer $69.95
Total Expenses $ 81.58

表达式: \$\s*[-+]?([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?)

匹配结果(标志 4):
[0]=> [0]$3.95
[1]=> [0]$1.00
[2]=> [0]$4.49
[3]=> [0]$2.19
[4]=> [0]$69.95
[5]=> [0]$ 81.58

此正则表达式模式可以按以下方式解释:

模式 | 子模式1 | 子模式2 |
\$ |  |  | 查找美元符号 $ . $ 前面包含一个反斜杠指示按字面解释美元符号, 而非将其作为正则表达式定位点. (单独的 $ 符号将指示正则表达式引擎应尝试在字符串的末尾开始匹配.)
\s* |  |  | 查找空白字符的 0 个或多个匹配项.
[-+]? |  |  | 查找正号或负号的 0 个或一个匹配项.
([0-9]{0,3}(,[0-9]{3})*(\.[0-9]+)?) |  |  | 圆括号将表达式定义为捕获组. 如果找到匹配项, 则有关匹配字符串的此部分信息可以从第二个捕获组对象中检索 (集合中的第一个元素表示整个匹配.). 查找对象分述如下:
 | ([0-9]{0,3}(,[0-9]{3})* |  | 查找对象分述如下:
 |  | [0-9]{0,3} | 查找十进制数字 0 到 9 的零到三个匹配项
 |  | (,[0-9]{3}* | 查找后跟三个十进制数字的组分隔符的零个或多个匹配项
 | (\.[0-9]+)? |  | 查找对象分述如下:
 |  | \. | 转义句点字符为原意文本字符. 匹配小数分隔符(小数点)
 |  | [0-9]+)? | 查找上项匹配值(小数点)后跟 1 或 多个十进制数字的 0 个或 1 个匹配项


正则表达式中的字符转义 \ 与反转义 \Q ...\E

正则表达式中的反斜线 (\) 指示以下值之一：

1. 后接字符为特殊字符, 如下表中所示. 例如 \b 指示正则表达式匹配应从单词边界开始的定位点, \t 表示制表符, 而 \x020 表示空白空间.

转义符 | 描述
\a | 与报警 (bell) 字符 (Chr(7)) 匹配.
\b | 匹配单词开头或结尾的分界处. 但在字符组中则匹配退格键 (Chr(8)).
\t | 匹配水平制表符 @TAB, Chr(9).
\r | 匹配回车符 @CR, Chr(13).
\v | 匹配垂直空白字符, 默认等效 \n\r 换行符+回车符. 还可匹配垂直制表符 (VT), 换页符 (FF) ; (当 UCP 启用时匹配: 下一行 (NEL), 行分隔符, 段落分隔符.)
\f | 匹配换页符 Chr(12).
\h | 匹配: 水平制表符 (HT), 空白, 非换行空格 (当 UCP 启用时增加: 欧甘文字空间标记, 蒙古文元音分隔符, 半角\全角空白, 半角\空格, 1/3 全角空格, 1/4 全角空格, 1/6 全角空格, 数字间空白, 标点符号空间, 窄空白, 最窄空白, 窄无中断空格, 中等数学空间, 表意字符空间.)
\s | 匹配 \h 内的所有字符加换行符(LF), 换页符(FF), 回车符(CR).
\n | 匹配换行符 @LF, Chr(10).
\e | 匹配转义符 \u001B, 控制字符 (Chr(27).
\nnn | 字符的八进制表示形式(nnn 由二位或三位数字组成). 如果此构造仅包含一位数字 (如 \2) 并且对应捕获组的编号, 则将它解释为向后引用. (参阅正则表达式中的反向引用构造)
\xnn | 匹配 16 进制的 Unicode 编码字符: \x7E 匹配一个波浪号 "~".
\x{nnnn} | 匹配 16 进制的 Unicode 编码字符: \x{20AC} 表示欧元符号, "€" 即 ChrW(0x20AC) .
\cX | 匹配 ASCII 控制符, X 是控制字符的字母. 例如 \cM 表示 CTRL-M, \cC 为 CTRL-C.

2. 本应解释为未转义语言构造的字符应按字面意思进行解释. 例如大括号 { 为限定符定义的开始, 而反斜杠后接大括号 \{ 表示正则表达式引擎应匹配大括号. 同理, 单个反斜杠标记转义语言构造的开始, 而两个反斜杠 \\ 表示正则表达式引擎应匹配反斜杠.
表达式中有特殊意义的字符, 应用到 字符组[...]或[^...], 或 分组子表达式(......) 中时, 需要添加 "\" 才能匹配该字符本身的字符汇总:

字符 | 说明 | 字符 | 说明
^ | 匹配输入字符串的开始位置. 要匹配 "^" 字符本身, 必须使用 \^ | . | 匹配除了换行符 (\n) 以外的任意一个字符. 要匹配小数点本身, 必须使用 \.
$ | 匹配输入字符串的结尾位置. 要匹配 "$" 字符本身, 必须使用 \$ | ? | 0 次或 1 次限定符. 要匹配 "?" 字符本身, 必须使用 \?
() | 标记子表达式的开始和结束位置. 要匹配小括号, 必须使用 \( 和 \) | + | 1 次或多次限定符. 要匹配 "+" 字符本身, 必须使用 \+
[] | 标记字符组的开始和结束位置. 要匹配中括号, 必须使用 \[ 和 \] | * | 0 次或多次限定符. 要匹配 "*" 字符本身, 必须使用 \*
{} | 限定符的开始和结束位置. 要匹配大括号, 必须使用 \{ 和 \} | | | 左右两边表达式的 "或" 关系符. 匹配 "|" 本身, 必须使用 \|
\ | 开始转义字符为正则表达式的特殊意义的字符. 要匹配 \ 必须使用 \\ |  |

上表的转义语法可使用 \Q ...\E 语句简化处理, 例如表达式 \Q(a+b)*3\E 可以匹配字符串 (a+b)*3, 其中的 (, +, ), * 则无需使用反斜杠 \ 符号进行转义.

注意: 字符转义可在正则表达式模式中识别, 但无法在替换模式中识别

示例:

以下示例说明如何使用正则表达式中的字符转义. 分析 2009 年世界上最大城市的名称及其人口的字符串. 使用制表符 \t 或垂直条 | 将每个城市名与其人口数量分开. 使用回车符和换行符分隔各个城市及其人口:

字符串:
Mumbai, India|13,922,125
Shanghai, China 13,831,900 ; 注意: 数字 13 前面应包含一个制表符 !
Karachi, Pakistan|12,991,000
Delhi, India 12,259,230 ; 注意: 数字 12 前面应包含一个制表符 !
Istanbul, Turkey|11,372,613

表达式: \G(.+)[\t|](.+)\r?\n
匹配结果(标志 4):
[0]=> [0]Mumbai, India|13,922,125
[1]=> [0]Shanghai, China 13,831,900
[2]=> [0]Karachi, Pakistan|12,991,000
[3]=> [0]Delhi, India 12,259,230
[4]=> [0]Istanbul, Turkey|11,372,613

表达式分析:

模式 | 说明
\G | 从上次匹配结束处开始匹配
(.+) | 一次或多次匹配任何字符. 这是第一个捕获组.
[\t|] | 匹配制表符 \t 或垂直条 | .
(.+) | 一次或多次匹配任何字符. 这是第二个捕获组.
\r?\n | 匹配 0 或 1 个回车符 \r, 后接换行符 \n.


正则表达式中的字符匹配

下表为正则表达式用于匹配各类字符的元素列表, 点击元素名查看详细描述.

元素名 | 描述
[...] | 正字符组. 方括号包围若干字符. 输入字符串的字符可以匹配组指定字符的某一个字符.
[^...] | 负字符组. 匹配字符时排除组指定的字符.
. | 匹配除换行符 \n 之外的任何字符.
\p{名称} | 匹配 Unicode 属性类别字符, 或 Unicode 属性命名块.
\P{名称} | 不匹配 Unicode 属性类别字符, 或 Unicode 属性命名块.
\w | 匹配任何单词字符.
\W | 匹配任何非单词字符.
\s | 匹配任何空白字符.
\S | 匹配任何非空白字符.
\d | 匹配任何十进制数字.
\D | 匹配任何非十进制数字.

注意: 字符组可以匹配 [...] 中包含的任意字符. 虽然可以是任意字符, 但只能匹配其中的一个.


正字符组: [...]

正字符组指定一个字符列表, 其中的任何一个字符可以出现在输入字符串中, 以便进行匹配. 可以包括一个或多个文本字符, 转义字符或字符类的任意组合.
此字符列表可以单独指定若干字符, 例如 [abc] 表示匹配一个字符 " a " 或一个 " b " 或一个 " c " .

字符组支持由连字符 " - " 表示的字符范围. 当 " - " 前后字符构成范围时, 要求前面的字符码位小于后面的字符码位.
例如 [a-z] 表示任意一个小写字母. 而使用 [z-a] 则会提示表达式错误.

大部分正则中有特殊意义的转义字符, 匹配其本身时需转义, 但在 [...] 内是不需要转义的. 必须转义的只有 " \ " , " [ " 和 " ] " .
而 "^" 出现在正字符组 [...] 开始位置则需要转义(否则将表示为排除型字符组), 例如 [\^.$^{\[(|)*+?-\\] 的 \^ 即转义 ^ 字符匹配本身; 出现在其它位置则不需要转义.

还有一点并不常见, \b 在字符组外表示单词边界, 但是在字符组内 [\b] 则表示退格符.

下表列出了一些正字符组的正则表达式示例:

模式 | 说明
[0-9] | 匹配 0~9 中任意一个数字, 等价于[0123456789]
[aeiou] | 匹配所有元音字母.
[\p{P}\d] | 匹配所有标点符号和十进制数字字符.
[\s\p{P}] | 匹配所有空白和中, 英文标点符号.
[ab5@] | 匹配 "a" 或 "b" 或 "5" 或 "@"

下面的示例定义包含字符 a 和 e 的正字符组, 以使输入字符串必须包含单词 grey 或 gray 且后跟另一个单词以便进行匹配:

字符串: The gray wolf jumped over the grey wall.

表达式: gr[ae]y\s\S+?[\s\p{P}]

匹配结果(标志 3):
[0]gray wolf
[1]grey wall.

表达式分析:

模式 | 说明
gr | 匹配文本字符 " gr ".
[ae] | 匹配一个 " a " 或 " e " 字符
y\s | 匹配文本字符 " y ", 并且后跟一个空格符.
\S+? | 匹配一个或多个非空白字符(但尽可能少), 即匹配字符 y 后空格跟随的一个单词 .
[\s\p{P}] | 匹配空白字符或标点符号.

下面的示例匹配以任何大写字母开头的单词. 子表达式字符组 [A-Z] 表示从 A 到 Z 的大写字母范围:

字符串: A city Albany Zulu maritime Marseilles

表达式: \b[A-Z]\w*\b

匹配结果(标志 3):
[0]A
[1]Albany
[2]Zulu
[3]Marseilles

正则表达式 \b[A-Z]\w*\b 分析:

模式 | 说明
\b | 匹配单词的开始位置.
[A-Z] | 正字符组. 匹配从 A 到 Z 的任意一个大写字符.
\w* | 匹配 0 个或多个单词字符.
\b | 匹配单词的结束位置.

示例 1 -- 连续 2 个相同的字符组

字符串: abc123

表达式: [bcd][bcd]

匹配结果: bc (选择标志 1, 或 2, 或 3 均可)
2 个相同的正字符组, 一个匹配 字符 b , 一个匹配字符 c .

示例 2 -- 字符组加限制符

字符串: ab|ac

表达式: [abc|]+

匹配结果: ab|ac (选标志 1, 2, 3, 4 均可)
这里的匹配结果能返回原字符串, 是因为使用了元字符 + 的原因.

示例 3

[0-9][0-9] 匹配字符串 Windows 2003 时, 匹配成功, 匹配的结果为 20 (测试标志 1 或 2).
2 个相同的数字字符组, 一个匹配数字 2, 另一个匹配数字 0.

下面是一个更复杂的表达式: \(?0\d{2}[) -]?\d{8}.

这个表达式可以匹配几种格式的电话号码, 像 (010)88886666, 或 022-22334455, 或 02912345678 等.

下面将这个表达式拆分为若干子模式对它进行一些分析:

模式 | 说明
\(? | 转义元字符 ( , 以便匹配圆开括号本身, ? 限制出现 1 次或不出现
0 | 匹配一个数字 0
\d{2} | 匹配 2 个数字
[) -]? | 匹配一个 ), 或一个 - , 或一个空格. ? 限制出现 1 次或不出现
\d{8} | 匹配 8 个数字

常见错误用法:

因为 [...] 本身表示的就是字符之间的 或 关系, 因此在 [...] 中使用 | 表示 或 关系是错误的.

举例: [a|b|c] 表示的是 a 或 b 或 c 或 | 中的任意一个字符. 正确写法应为 [abc|].


[^... ] 负字符组 (排除型字符组)

负字符组指定一个字符列表, 匹配过程排除列表包含的字符. 此字符列表可以单独指定和/或作为范围指定. 可以包括一个或多个文本字符, 转义字符或字符类的任意组合.

可以连接两个或更多字符范围. 例如, 若要排除从 0 至 9 的十进制数范围, 和从 a 至 f 的小写字母范围, 以及从 A 至 F 的大写字母范围, 则可使用 [^0-9a-fA-F] .

[^abc] 表示匹配时必须排除字符 a , b , c . 负字符组中的前导符 ^ 是强制的, 指示字符组为负字符组, 而不是正字符组.

下表列出了一些常见负字符组的正则表达式模式:

模式 | 匹配内容
[^\x00-\xff] | 排除 0 到 255 的所有 ANSI 字符. 即匹配任意一个汉字. [^\x00-\xff]+ 匹配连续的汉字.
[^\p{P}\d] | 匹配标点符号和十进制数字字符以外的所有字符.
[^aeiou] | 匹配除元音以外的所有字符.

下面示例匹配以字符 th 开头且后面不跟 o 的任何单词:

字符串: thought thing though them through thus thorough this

表达式: \bth[^o]\w+\b

匹配结果(标志 3):
[0]thing
[1]them
[2]through
[3]thus
[4]this

正则表达式分析:

模式 | 说明
\b | 匹配单词的开始位置.
th | 匹配文本字符 th .
[^o] | 负字符组. 匹配任何不是字母 o 的字符.
\w+ | 匹配一个或多个单词字符.
\b | 匹配单词的结束位置.

新手最容易犯的错误就是, 用 [^abc] 或 [^(abc)] 这样的表达式来匹配不包含 "abc" 子字符串的字符串.

例如:

源字符串: "<aaa>bbb<abc>ccc<ddd>"

规则描述: 取出源字符串中格式为<...>, 但<>中不是 abc 的内容.

预期结果: <aaa>、<ddd> (测试标志 3)

错误写法: <[^abc]*> (测试标志 1, 2, 3, 4 都只能匹配 <ddd>)

正确写法: "<(?!abc>)[^>]*>"

表达式分析:

模式 | 说明
< | 开始匹配一个左尖括号 <
(?!abc>) | 负预测先行断言, ?! 为负向预取, 表示从这个位置开始不匹配字符串 abc> . 即跳过左尖括号 < 后面跟随的 abc> 字符串.
[^>]* | 负字符组. 匹配 0 或多个不是 > 的其它字符. 即匹配左尖括号 < 后面不是字符串 abc> , 只到下面子模式指定模式前的所有字符.
> | 跟着匹配一个右尖括号 > 完成一次匹配过程.


任意字符: .

句点字符 . 匹配除 \n 换行符之外的任何字符. 有以下两个注意点:

1. 当选项 (?s) 激活时匹配换行符.

2. 句点字符在字符组内部 [.], 则只能匹配点号本身.

下面示例使用 . 的不同匹配行为. 正则表达式 ^.+ 从字符串开头开始, 并匹配每个字符. 默认匹配到第一行的结尾结束; 模式可以匹配回车符 \r ，但不匹配换行符 \n.

字符串:
This is one line and
this is the second.

表达式: ^.+

测试结果只能返回第一行的文本字符串.

但单行模式选项 (?s) 可以将整个输入字符串解释为单行, 因此 (?s) 选项激活时将匹配输入字符串中的每个字符, 包括换行符 \n.

仍然使用上面的字符串, 表达式修改为 (?s)^.+, 此时能完整匹配源字符串的 2 行文本字符串.

下面示例通过定义包括句点字符 . 的正则表达式, 作为正字符组的成员来进行演示:

正则表达式 \b.*[.?;:](\s|\z) 在字边界处开始, 匹配任何字符直到遇到四个标点符号之一(包括句点), 然后匹配空白字符或字符串的末尾.

字符串: this; what: is? go, thing.

表达式: \b.*[.?;:](\s|\z)

匹配结果(标志 4): [0]=> [0]his; what: is? go, thing.

表达式分析:

模式 | 说明
\b | 在单词开头边界处开始匹配
.* | 任意字符连续重复匹配多次
[.?;:] | 正字符组, 一次匹配标点符号 . ? ; : 中的一个.
(\s|\z) | 包含选项的分组, 匹配任何空白字符, 包含回车符, 换行符, 制表符, 空格符, 或者匹配输入字符串的结束位置.

由于 . 匹配任何字符, 因此当正则表达式模式尝试多次匹配任何字符时, 句点字符 . 通常会与惰性限定符一起使用.


Unicode 字符属性

Unicode 标准为每个常规类别分配一个字符. 例如, 特定字符可以是大写字母(由 Lu 类别表示), 十进制数字(Nd 类别), 数学符号(Sm 类别)或段落分隔符(Zl 类别).

有关类别缩写的列表如下(未经全部测试):

类别 | 说明 | 类别 | 说明
Lu | 大写字母 | Ll | 小写字母
Lt | 首字母大写 | Lm | 修饰符字母
Lo | 其它字母 | L | 所有字母字符. 包括 Lu、Ll、Lt、Lm 和 Lo 字符
Mn | 标记 -- 非间距 | Mc | 标记 -- 间距组合
Me | 标记 -- 封闭 | M | 所有的注音符号标记. 包括 Mn、Mc 和 Me 类别
Nd | 十进制数字 | Nl | 数字, 字母
No | 其它数字 | N | 所有数字. 包括 Nd、Nl 和 No 类别
P | 所有标点字符, 这包括 Pc、Pd、Ps, Pe、Pi、Pf 和 Po 类别 | Pc | 标点符号 -- 连接符
Pd | 标点符号 -- 短划线 | Pe | 标点符号 -- 结束
Ps | 标点符号 -- 开始 | Pi | 标点符号 -- 前引号(根据具体使用情况, 作用可能像 Ps 或 Pe)
Pf | 标点符号 -- 后引号(根据具体使用情况, 作用可能像 Ps 或 Pe) | Po | 标点符号 -- 其他
S | 所有符号. 包括 Sm、Sc、Sk 和 So 类别 | Sm | 数学符号
Sc | 货币符号 | Sk | 修饰符符号
So | 其它符号 |  |
Zs | 分隔符 -- 空白 | Zl | 分隔符 -- 行
Zp | 分隔符 -- 段落 | Z | 所有分隔符字符. 这包括 Zs、Zl 和 Zp 类别
Cc | 其它 -- 控制符 | Cf | 其他 -- 格式
Cs | 其它 -- 代理项 | Co | 其它 -- 私用
Cn | 其它 -- 未赋值(任何字符都不具有此属性) | C | 所有控制字符. 包括 Cc、Cf、Cs、Co 和 Cn 类别

Unicode 标准中的特定字符集也占据连续码位的特定区域或块. 例如可在 \u0000 和 \u007F 之间找到基本拉丁字符集, 也可在 \u0400 和 \u04FF 之间找到西里尔语字符集

源资料命名块有 100 多条, 下表仅列出有示例并且经测试通过的 2 个命名块, 以及 AutoIt 帮助提到的 1 个命名块. 支持的命名块基于 Unicode 4.0 和 Perl 5.6

码位范围 | 块名称 | 码位范围 | 块名称
0370 - 03FF | Greek | 0000 - 007F | Latin
0400 - 04FF | Cyrillic |  |


匹配 Unicode 类别或块: \p{名称}

匹配属于 Unicode 常规类别或命名块的任何字符, 其中名称是类别缩写或命名块的名称.

下面的示例使用 \p{名称} 构造以匹配 Unicode 常规类别(示例中 Pd 为短划线).

字符串: Κατα Μαθθαίον - The Gospel of Matthew

表达式: \p{Greek}+(\s)?(\p{Greek}+(\s)?)+\p{Pd}\s\p{Latin}+(\s)?(\p{Latin}+(\s)?)+

匹配结果(标志 2):
[0]Κατα Μαθθαίον - The Gospel of Matthew
[1]
[2]Μαθθαίον
[3]
[4]
[5]Matthew
[6]
其中 [1], [3], [4], [6] 为空白子符.

表达式分析:

模式 | 说明
\p{Greek}+ | 匹配一个或多个希腊语字符.
(\s)? | 匹配零个或一个空白字符.
(\p{Greek}+(\s)?)+ | 匹配一个或多个希腊语字符后跟零个或一个空白字符集合的一次或多次.
\p{Pd} | 匹配短划线字符.
\s | 匹配空白字符.
\p{Latin}+ | 匹配一个或多个基本拉丁字符.
(\s)? | 匹配零个或一个空白字符.
(\p{Latin}+(\s)?)+ | 匹配一个或多个基本拉丁字符后跟零个或一个空白字符模式的一次或多次.

匹配非 Unicode 类别或块: \P{}

下面的示例使用 \P{名称} 构造来从数字字符串中删除任何货币符号(在该示例中 Sc 为货币符号标记).

字符串: $164,091.78, £1,073,142.68, €73, €120

表达式: (\P{Sc})+

匹配结果(标志 4):
[0]=> [0]164,091.78,
[1]=> [0]1,073,142.68,
[2]=> [0]73,
[3]=> [0]120

正则表达式模式 (\P{Sc})+ 匹配不为货币符号的一个或多个字符, 它能有效地从结果字符串中抽出任何货币符号.


单词字符: \w

\w 与任何单词字符匹配, 是正字符组 [a-zA-Z_0-9_] 的简记形式, 匹配任何单词字符: 任何数字, 任意字母或下划线 _ .

\w 匹配任何单词字符: 任何数字, 任意字母或下划线 "_"

(* UCP)\w 激活 UCP 选项时匹配下表所列的任何 Unicode 数字, 任何语言中的任何 Unicode 字母(包含汉字), 下划线 _ .

类别 | 说明 | 类别 | 说明
Lu | 大写字母 | Ll | 小写字母
Lt | 首字母大写 | Lm | 修饰符字母
Lo | 其它字母 | L | 所有字母字符. 包括 Lu、Ll、Lt、Lm 和 Lo 字符
Nd | 十进制数数字 | Pc | 连接符, 此类别包含 10 个字符, 常见的是下划线 _ .

由于它匹配任何单词字符, 因此当正则表达式模式尝试多次匹配任何单词字符且后跟特定单词字符时, \w 通常会与惰性限定符一起使用.

下面的示例使用 \w 匹配单词中的重复字符:

字符串:
trellis, seer, latter, summer,
hoarse, lesser, aardvark, stunned

表达式: (\w)\1

匹配结果(标志 4) 说明如下:
[0]=> [0]ll 开始于单词 trellis 的位置 3
[1]=> [0]ee 开始于单词 seer 的位置 1
[2]=> [0]tt 开始于单词 latter 的位置 2
[3]=> [0]mm 开始于单词 summer 的位置 2
[4]=> [0]ss 开始于单词 lesser 的位置 2
[5]=> [0]aa 开始于单词 aardvark 的位置 0
[6]=> [0]nn 开始于单词 stunned 的位置 3
单词 hoarse 没有重复的字符

表达式分析:

元素 | 说明
(\w) | 匹配单词字符, 这是第一个捕获组.
\1 | 匹配第一次捕获的值.


非单词字符: \W

\W 为负字符组 [^a-zA-Z_0-9_] 的简记形式. 由于它匹配任何非单词字符, 因此当正则表达式模式尝试多次匹配任何非单词字符且后跟特定非单词字符时, \W 通常会与惰性限定符一起使用.

下面的示例阐释 \W 定义正则表达式模式 \b(\w+)(\W){1}, 该模式匹配后跟一个或两个非单词字符(例如空白或标点符号)的单词:

字符串: The old, grey mare slowly walked across the narrow, green pasture.

表达式: \b(\w+)(\W){1}

匹配结果(标志 3)这个例子显示输出说明如下:
[0]The 单词
[1] 空格
[2]old 单词
[3], 标点符号
[4]grey 单词
[5] 空格
[6]mare 单词
[7] 空格
[8]slowly 单词
[9] 空格
[10]walked 单词
[11] 空格
[12]across 单词
[13] 空格
[14]the 单词
[15] 空格
[16]narrow 单词
[17], 标点符号
[18]green 单词
[19] 空格
[20]pasture 单词
[21]. 标点符号

正则表达式分析如下:

模式 | 说明
\b | 匹配单词开始位置.
(\w+) | 匹配一个或多个单词字符. 这是第一个捕获组.
(\W){1} | 匹配非单词字符一次, 这是第二个捕获组, 包含 1 个捕获的空格或标点符号.


空白字符：\s

\s 匹配任何空白字符. 它等效于下表中列出的转义序列和 Unicode 类别.

\f | 匹配换页符 (Chr(12)).
\n | 匹配换行符 (@LF, Chr(10)).
\r | 匹配回车符 (@CR, Chr(13)).
\t | 匹配水平制表符 (@TAB, Chr(9)).
\v | 匹配任何垂直空白字符. 包括换行符 (LF), 垂直制表符 (VT), 换页符 (FF), 回车符 (CR), 当 (*UCP) 启用时匹配: 下一行 (NEL), 行分隔符, 段落分隔符.
\p{Z} | 匹配任何空白分隔符.

下面示例 \s 定义正则表达式模式 \b\w+(e)?s(\s|$), 该模式匹配以 s 或 es 结尾且后跟一个空白的单词字符, 或匹配输入字符串的结束位置:

字符串: matches stores stops leave leaves

表达式: \b\w+(e)?s(\s|$)

匹配结果(标志 4):
[0]=> [0]matches
[1]=> [0]stores
[2]=> [0]stops
[3]=> [0]leaves

单词 leave 包含字符 e , 但 e 后不是 s , 所以此单词不匹配.

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
\w+ | 匹配一个或多个单词字符.
(e)? | 匹配字符 e 0 次或一次
s | 匹配字符 s
(\s|$) | 包含条件选项的分组 , | 为选项分隔符. 匹配空白字符, 或输入字符串的结束位置.


非空白字符：\S

\S 匹配任何非空白字符. 等效于负字符组 [^\f\n\r\t\v] , 与空白字符 \s 的正则表达式模式相反.

下面的示例阐释 \S 语言元素. 正则表达式模式 \b(\S+)\s? 匹配由空白字符分隔的单词字符串:

字符串:
This is the first sentence of the first paragraph.
This is the second sentence.
This is the only sentence of the second paragraph.

表达式: \b(\S+)\s?

返回结果(选项 3):
[0]This
[1]is
[2]the
[3]first
[4]sentence
[5]of
[6]the
[7]first
[8]paragraph.
[9]This
[10]is
[11]the
[12]second
[13]sentence.
[14]This
[15]is
[16]the
[17]only
[18]sentence
[19]of
[20]the
[21]second
[22]paragraph.

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
(\S+) | 匹配一个或多个非空白字符. 这是一个捕获组.
\s? | 匹配 0 个或一个空白字符. 替换为 \p{Z}? 效果相同 .


十进制数字字符: \d

\d 为正字符组 [0-9] 的简记形式. 匹配任何十进制数字. 当 (*UCP) 启用时匹配任何语言的任何 Unicode 十进制数字.

下面示例 \d 测试输入字符串是否为美国和加拿大的有效电话号码:

字符串:
111 111-1111, 222-2222, 222 333-444,
(212) 111-1111, 111-AB1-1111,
212-111-1111, 01 999-9999

表达式: (\(?\d{3}\)?[\s-])?\d{3}-\d{4}

匹配结果(标志 4):
[0]=> [0]111 111-1111
[1]=> [0]222-2222
[2]=> [0](212) 111-1111
[3]=> [0]212-111-1111

表达式分析:

模式 | 子模式 | 说明
(\(?\d{3}\)?[\s-])? |  | 这是一个捕获组. 匹配 0 次或 1 次下列 4 项子模式的匹配集合 .
 | \(? | 转义 ( 为本身字面意义的字符 , 匹配 0 个或一个 ( 文本字符.
 | \d{3} | 匹配三个十进制数字.
 | \)? | 转义 ) 为本身字面意义的字符 , 匹配 0 个或一个 ) 文本字符.
 | [\s-] | 匹配一个空白字符, 或一个连字符.
\d{3}-\d{4} |  | 匹配三个十进制数字后跟连字符和四个十进制数字.


非数字字符: \D

\D 匹配任何非数字字符. 负字符组 [^0-9] 的简记形式.

下面示例 \D 测试部件号字符串是否包含适当的十进制和非十进制数字字符的组合:

字符串: "A1039C", "AA0001", "C18A", "Y938518"

表达式: \b\D\d{1,5}\D?\b

匹配结果(标志 3):
[0]A1039C
[1]C18A

不匹配的原因 : "AA0001" 最后一位是数字 , 不符合表达式 \D? 的要求 ; "Y938518" 有 6 位数字 , 超出表达式 \d{1,5} 限制 .

表达式分析:

模式 | 说明
\b | 匹配单词的开始位置.
\D | 匹配非数字字符.
\d{1,5} | 匹配 1 到 5 个十进制数字.
\D? | 匹配 0 个或一个非十进制字符.
\b | 匹配单词的结束位置.


正则表达式中的锚点

定位锚点(原子零宽度断言)指定字符串中必须出现匹配的位置. 在表达式中使用定位点时, 正则表达式引擎不在字符串中前进或使用字符, 它仅在指定位置查找匹配.
例如 ^ 指定必须从行或字符串的开头开始匹配. 因此, 正则表达式 ^http: 仅当 "http:" 出现在行开头时才与之匹配.

下表列出了 AutoIt 中正则表达式支持的定位锚点, 点击锚点标识查看详细描述:

锚点标识 | 说明
^ | 在字符组的外部, 匹配主题文本的开始位置. 如果多行选项 (?m) 激活, 则只是在一个非最终换行符序列的后面. 默认换行序列为 @CRLF. 在字符组的内部, 首位 ^ 表示排除字符组中列出的字符.
$ | 在字符组的外部, 匹配主题文本的末尾, 如果多行选项 (?m) 激活, 则仅匹配在换行符序列之前. 在字符组的内部, $ 表示本身，即一个美元符号.
\A | 仅在绝对主题字符串的开头匹配, 忽略多行选项 (?m). 如果偏移量不是 1 将永远不会匹配.
\Z | 仅匹配主题字符串的结束, 或在一个换行符序列 \n 结束之前, 忽略多行选项 (?m).
\z | 仅匹配主题字符串的结束, 忽略多行选项 (?m).
\G | 匹配主题字符串当前位置的第一个匹配项. -- 匹配必须从上一个匹配结束的位置开始.
\b | 匹配单词的开头或结尾, 也就是单词的边界处.
\B | 匹配不得出现在字边界上.


字符串或行的开头: ^

^ 定位点指定后面模式必须从字符串的第一个字符位置开始. 如果多行选项 (?m) 激活, 则匹配必须出现在每行的开头.

以下示例在正则表达式中使用 ^ 定位点, 可提取有关某些职业棒球队参赛年限的信息. 匹配方法有 2 种:

1. 常规匹配方法 -- 只能匹配第一行的文本及其子字符串;

2. 使用多行选项 (?m) 可找到所有五行文本及其子字符串.

字符串:
Brooklyn Dodgers, National League, 1911, 1912, 1932-1957
Chicago Cubs, National League, 1903-present
Detroit Tigers, American League, 1901-present
New York Giants, National League, 1885-1957
Washington Senators, American League, 1901-1960

表达式: (?m)^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+

匹配结果(标志 4):
[0]=> [0]Brooklyn Dodgers, National League, 1911, 1912, 1932-1957
[1]=> [0]Chicago Cubs, National League, 1903-present
[2]=> [0]Detroit Tigers, American League, 1901-present
[3]=> [0]New York Giants, National League, 1885-1957
[4]=> [0]Washington Senators, American League, 1901-1960

[0]=> [1]Brooklyn Dodgers
[0]=> [2]Dodgers
[0]=> [3]
[0]=> [4]National League
[0]=> [5] 1932-1957
[0]=> [6]-1957
[0]=> [7]1957 		[1]=> [1]Chicago Cubs
[1]=> [2]Cubs
[1]=> [3]
[1]=> [4]National League
[1]=> [5] 1903-present
[1]=> [6]-present
[1]=> [7]present 		[2]=> [1]Detroit Tigers
[2]=> [2]Tigers
[2]=> [3]
[2]=> [4]American League
[2]=> [5] 1901-present
[2]=> [6]-present
[2]=> [7]present 		[3]=> [1]New York Giants
[3]=> [2]Giants
[3]=> [3]
[3]=> [4]National League
[3]=> [5] 1885-1957
[3]=> [6]-1957
[3]=> [7]1957 		[4]=> [1]Washington Senators
[4]=> [2]Senators
[4]=> [3]
[4]=> [4]American League
[4]=> [5] 1901-1960
[4]=> [6]-1960
[4]=> [7]1960

表达式分析:

模式 | 子模式 | 说明
(?m)^ |  | 激活多行选项, 从每行的开头开始匹配.
((\w+(\s?)){2,}) |  | 匹配以下 2 个子模式的组合项. 第 1 捕获组, 匹配球队名 .
 | \w+ | 匹配 1 或多个单词字符. 这是第 2 捕获组, 匹配球队名的最后一个单词 .
 | (\s?) | 匹配 0 或 1 个空白符. 这是第 3 捕获组
 | {2,} | 匹配第 2 和第 3 捕获组的组合项至少 2 次
,\s |  | 匹配后跟一个空白字符的逗号.
(\w+\s\w+) |  | 匹配以下 3 个子模式的组合项. 这是第 4 捕获组, 匹配赛场名 .
 | \w+ | 匹配 0 或多个单词字符.
 | \s | 匹配一个空白符
 | \w+ | 匹配 0 或多个单词字符.
, |  | 匹配一个逗号.
(\s\d{4}(-(\d{4}|present))?,?)+ |  | 这是第 5 捕获组. 匹配以下子模式的组合项( 与第 6 和 7 捕获组匹配球队的参赛年限 ) .
 | \s\d{4} | 匹配空格后跟 4 个十进制数字.
 | (-(\d{4}|present))? | 这是第 6 和第 7 捕获组, 匹配一个连字符后跟 4 个十进制数字, 或后跟字符串 present 组合项的 0 次 或 1 次.
 | ,? | 匹配 0 个或 1 个 逗号
 | + | 1 次或多次匹配第 5 捕获组的匹配项


字符串或行的末尾: $

$ 定位点指定前面的模式必须出现在输入字符串的末尾, 或出现在输入字符串末尾的 \n 换行符之前. 如果激活多行选项 (?m) , 则匹配也可以出现在行的末尾.

请注意, $ 与 \n 匹配但与 \r\n (回车符和换行符的组合, 或称 CR/LF) 不匹配. 若要匹配 CR/LF 字符组合, 请将 \r?$ 包括到正则表达式模式中.

以下示例将 $ 定位点添加到字符串或行的开头示例中使用的正则表达式模式 ^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+ 中. 配合包括五行文本的原始输入字符串使用时, 常规匹配方法找不到匹配项, 因为第一行的末尾与 $ 模式不匹配. 如果调用多行选项 (?m), 则将再次找到五个匹配项.

修改后的表达式: (?m)^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+$

测试结果和表达式分析参见字符串或行的开头.

也可以在 + 号后添加 \r 匹配回车符, 效果相同, 但输入字符串的最后一行必须要有一个回车操作.


仅字符串的开头: \A

\A 定位点指定匹配必须出现在输入字符串的开头. 它等同于 ^ 定位点, 只不过 \A 将忽略多行选项 (?m). 因此, 在多行的输入字符串中, 它只能匹配第一行的开头.

以下示例与 ^ 和 $ 定位点的示例类似. 它在正则表达式中使用 \A 定位点, 可提取有关某些职业棒球队存在年限的信息.

字符串:
Brooklyn Dodgers, National League, 1911, 1912, 1932-1957
Chicago Cubs, National League, 1903-present
Detroit Tigers, American League, 1901-present
New York Giants, National League, 1885-1957
Washington Senators, American League, 1901-1960

表达式: \A((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+

匹配结果(标志 4):
[0]=> [0]Brooklyn Dodgers, National League, 1911, 1912, 1932-1957
[0]=> [1]Brooklyn Dodgers
[0]=> [2]Dodgers
[0]=> [3]
[0]=> [4]National League
[0]=> [5] 1932-1957
[0]=> [6]-1957
[0]=> [7]1957

表达式分析:

模式 | 子模式 | 说明
\A |  | 从输入字符串的开头开始匹配.
((\w+(\s?)){2,}) |  |
 | \w+ | 匹配 1 或多个单词字符.
 | (\s?) | 匹配 0 或 1 个空白字符.
 | {2,} | 匹配上面两个子模式捕获结果 2 次
,\s |  | 匹配逗号后跟空白符.
(\w+\s\w+), |  | 匹配 1 个单词, 后跟一个空白字符, 再跟一个单词.
(\s\d{4} |  | 匹配一个空白字符后跟 4 个数字字符.
(-(\d{4}|present))? |  |
 | (-(\d{4} | 匹配连字符后跟 4 个数字字符.
 | |present) | 如果上面匹配失败则匹配字符串 present .
 | ? | 匹配上面子表达式捕获结果的 0 次或 1 次
,?)+ |  | 1 次或多次匹配 (-(\d{4}|present))? 结果后跟 0 或 1 个逗号的匹配结果

输入字符串包括五行. 由于 \A 的匹配限制, 此方法仅找到输入字符串中与正则表达式模式匹配的第一行文本及其子字符串.


字符串末尾或结束换行之前: \Z

\Z 定位点指定匹配项必须出现在输入字符串的末尾, 或出现在输入字符串末尾的 \n(换行符)之前. 它等同于 $ 定位点, 只不过 \Z 忽略多行选项 (?m).

因此, 在多行字符串中, 它只能匹配最后一行的末尾, 或 \n(换行符) 前的最后一行.

请注意, \Z 与 \n(换行符) 匹配但与 \r\n (回车与换行符)的组合不匹配.

以下示例在正则表达式中使用 \Z 定位点, 输入字符串与 字符串头 \A 的示例相同.

正则表达式 ((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+\Z 可提取有关某些职业棒球队存在年限的信息.

匹配结果(标志 4):
[0]=> [0]Washington Senators, American League, 1901-1960
[0]=> [1]Washington Senators
[0]=> [2]Senators
[0]=> [3]
[0]=> [4]American League
[0]=> [5] 1901-1960
[0]=> [6]-1960
[0]=> [7]1960

表达式分析参见字符串头 \A

由于 \Z 的匹配限制, 这个表达式只能匹配 5 行文本的最后一行文本.

仅字符串末尾：\z

\z 定位点指定匹配必须出现在输入字符串末尾. 与 $ 语言元素类似, \z 将忽略多行选项 (?m). 与 \Z 语言元素不同, \z 不匹配字符串末尾的 \n 换行字符. 因此, 它只能匹配输入字符串的最后一行.

以下示例在正则表达式中使用 \z 定位点, 与上一部分的示例中使用的定位点在其他方面相同, 用于提取有关某些职业棒球队存在年限的信息.

此示例尝试使用正则表达式模式 ^((\w+(\s?)){2,}),\s(\w+\s\w+),(\s\d{4}(-(\d{4}|present))?,?)+\r?\z 匹配字符串数组中五个元素的每一个.

5 行字符串中, 两行字符串以回车符和换行符结尾, 一行字符串以换行符结尾, 另外两行既不以回车符也不以换行符结尾. 只有不包含回车符或换行符的字符串与模式匹配.

此例的输入字符串无法组织, 因此也无法测试 !


单词边界：\b

\b 定位符指定匹配必须出现在单词字符 (\w*) 和非单词字符 (\W) 之间的边界位置. \b 是零宽度的.
(\w) 为正字符组 [a-zA-Z0-9_] 的简记形式 . 包括字母, 数字和下划线的字符; (\W) 为负字符组 [^a-zA-Z0-9_] 的简记形式, 包括不为字母, 数字或下划线的其它字符.
\b 匹配也可以出现在字符串开头或结尾处的单词边界. \b 定位点经常用于确保子表达式与整个单词匹配, 例如 \b\w+\b 能完整匹配输入语句中的每个单词.

\b 基础应用

\b 一般应用在需要匹配某一单词字符组成的子串, 但这个子串不能出现在更长的子串中, 例如 \babc\b 匹配 abc , 但不匹配 abcd.
比如要替换掉一段英文中的单词 " to ", 而 " today" 的 to 显然不在替换的范围内, 所以可以用正则表达式 \bto\b 来限定.

举例: 统计以逗号 , 分割的数字串中数值 3 的个数:

字符串: 137,1,33,4,3,6,21,3,35,93,2,98

表达式: \b3\b 匹配单个数字字符 3

匹配结果(标志 3): [0]3 [1]3
结果: 发现 2 个数值 3.

再看下面示例( 没弄明白这个示例中的 \b 是如何定位的 ):

字符串: abc_123中文_d3=efg汉字%

表达式: .\b.

匹配结果(标志 3): [0]3中 [1]文_ [2]3= [3]g汉

特殊情况

\b 用在正则中, 通常都是表示单词边界的, 但在字符组中, 它表示的是退格键,
即 [a-z\b] 中 \b 表示的是退格键, 而不是单词边界.

以下示例正则表达式 \bare\w*\b 用法. 它与任何以子字符串 " are " 开头的单词匹配. 该示例的输出说明 \b 与输入字符串符合指定单词的开头和结尾均匹配.

字符串: area bare arena mare

表达式: \bare\w*\b

匹配结果(标志 3): [0]area ; 从位置 0 开始匹配 [1]arena ; 从位置 0 开始匹配

bare 与 mare 虽然包含子串 are , 但都不是单词的开头子串 , 不符合 \b 匹配模式 .

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配. 确定匹配条件的子字符串位于单词的开头位置 .
are | 匹配子字符串 " are " . 指定表达式的匹配条件 .
\w* | 匹配前面指定条件的 0 个或多个单词字符. 这里只有 2 个单词符合指定条件 .
\b | 在单词边界处结束匹配.

下面示例可选多条件的 \b 应用:

字符串:
if(ifdo)
dosome();
else
doelse();

表达式: \b(if|while|else|void|int)\b

匹配结果(标志3): [0]if [1]else

表达式分析:

模式 | 说明
\b | 在单词边界的开始位置匹配
(if|while|else|void|int) | 一个 5 选项的捕获组 , | 为选项分隔符, 此例字符串仅有 2 个单词符合这里指定的选项 .
\b | 在单词边界的结束位置结束匹配


非字边界: \B

\B 定位符指定匹配不得出现在单词边界上. 它与 \b 定位点作用截然相反.

以下示例使用 \B 定位点定位单词中的子字符串 " qu " 匹配项. 正则表达式模式 \Bqu\w+ 指定子字符串 " qu " , 但 " qu " 并不位于单词之首, 延续匹配到单词末尾的子字符串.

字符串: equity queen equip acquaint quiet

表达式: \Bqu\w+

匹配结果(标志 3):
[0]quity ; 从位置 1 开始匹配. [1]quip ; 从位置 14 开始匹配. [2]quaint ; 从位置 21 开始匹配.

queen 与 quiet 包含的子字符串 qu 都位于单词的开头 , 不符合 \B 的匹配模式 .

表达式分析

模式 | 说明
\B | 不在单词边界处开始匹配. 确定匹配条件的子字符串不在单词的开头位置 .
qu | 匹配子字符串“qu”. 指定 \B 的匹配条件 .
\w+ | 匹配一个或多个单词字符. 这里 5 个单词只有 3 个单词符合指定条件 .


连续匹配: \G

\G 定位符指定匹配必须出现在上一个匹配结束的点. 此定位点可确保所有匹配项是连续的.

以下示例使用 \G 的正则表达式从一个以逗号分隔的字符串中提取啮齿类动物的名称:

字符串: capybara,squirrel,chipmunk,porcupine,gopher,beaver,groundhog,hamster,guinea pig,gerbil,chinchilla,prairie dog,mouse,rat

表达式: \G(\w+\s?\w*),?

匹配结果(标志 3):
[0]capybara
[1]squirrel
[2]chipmunk
[3]porcupine
[4]gopher
[5]beaver
[6]groundhog
[7]hamster
[8]guinea pig
[9]gerbil
[10]chinchilla
[11]prairie dog
[12]mouse
[13]rat

表达式分析:

模式 | 组内子模式 | 说明
\G |  | 继续上次匹配结束的位置开始.
(\w+\s?\w*) |  | 匹配后跟 0 个或 1 个空格再后跟 0 个或多个单词字符的一个或多个单词字符. 这是第一个捕获组.
 | \w+ | 匹配 1 个或多个单词字符.
 | \s? | 匹配 0 个或 1 个空格.
 | \w* | 匹配 0 个或多个单词字符.
,? |  | 匹配 0 个或 1 个文本逗号字符.

如果表达式启用 (*UCP) , 则可以匹配动物的中文名称:

字符串: 水豚,松鼠,花鼠,豪猪,鼠,海狸,土拨鼠,仓鼠,豚鼠,沙鼠,栗鼠,草原犬鼠,小鼠,大鼠

表达式: (*UCP)\G(\w+\s?\w*),?


正则表达式中的限定符

限定符指定匹配输入文本中的字符, 或组的多少个实例才能找到匹配项.下表列出可用的限定符, 点击蓝色字体查看详细描述:

贪婪 | 惰性 | 占有 (AutoIt 文档描述的) | 说明
* | *? | *+ | 匹配零次或多次.
+ | +? | ++ | 匹配一次或多次.
? | ?? | ?+ | 匹配零次或一次.
{x} | {x}? | {x}+ | 准确匹配 x 次.
{x,} | {x,)? | {x,}+ | 至少匹配 x 次.
{x,y) | {x,y}? | {x,y}+ | 至少匹配 x 但不超过 y 次.

量词 x 和 y 为正整数值. 通常限定符是贪婪的, 它们使正则表达式引擎将尽可能多地匹配特定模式的匹配项. 通俗点讲, 就是看到想要的, 有多少就捡多少, 除非再也没有想要的了.
量词后追加 ? 字符限定符使其成为惰性的, 它使正则表达式引擎可以尽可能少的返回匹配项. 通俗点讲, 就是找到一个想要的捡起来就行了, 至于还有没有没捡的就不管了.
有关贪婪限定符与惰性限定符之间差别的完整描述, 请参见 贪婪与惰性限定符.

嵌套限定符(例如正则表达式模式 (a*)* 的操作)可以增加正则表达式引擎必须执行的比较次数.
关于此行为和其解决方法的更多信息, 请参见正则表达式的回溯.

如果在正则表达式模式中遇到 *, +, ?, { 和 } 字符, 正则表达式引擎将它们解释为限定符或限定符构造的一部分, 除非它们包括在字符组中.
若要在正则表达式中将其解释为量词限定符的本身文本字符, 必须通过在前面加一个反斜杠进行转义. 例如正则表达式模式中的字符串 \* 被解释为原义星号 “*” 字符.


匹配 0 次或多次: *

* 限定符匹配前面元素 0 次或多次. 等效于 {0,} 限定符, * 是贪婪限定符, 对应的惰性限定符是 *?.

下面示例演示输入字符串内空格分隔的 9 个数字中, 有 5 个与模式匹配, 有 4 个（95、929、9129 和 9919）不匹配

字符串: 99 95 919 929 9119 9219 999 9919 91119

表达式: \b91*9*\b

匹配结果(标志 3):
[0]99 ; 开始于位置 0
[1]919 ; 开始于位置 6
[2]9119 ; 开始于位置 14
[3]999 ; 开始于位置 24
[4]91119 ; 开始于位置 33

表达式分析:

模式 | 说明
\b | 在单词边界处开始
91* | 匹配字符 9 并后跟 0 或多个字符 1 .
9* | 匹配 0 个或多个字符 9 .
\b | 在单词边界处结束

匹配 0 次或多次(惰性匹配): *?

*? 限定符可以匹配前导元素一次或多次, 但次数尽可能少. 它是贪婪限定符 * 对应的惰性部分.

在下面的示例中, 正则表达式 \b\w*?oo\w*?\b 与包含字符串 oo 的所有词匹配

字符串: woof root root rob oof woo woe

表达式: \b\w*?oo\w*?\b

匹配结果(标志 3):
[0]woof
[1]root
[2]root
[3]oof
[4]woo

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
\w*? | 匹配字符串 oo 前面 0 个或多个单词字符, 但字符尽可能少.
oo | 匹配字符串 oo .
\w*? | 匹配字符串 oo 后面 0 个或多个单词字符, 但字符尽可能少.
\b | 在单词边界处结束.


匹配一次或多次: +

+ 限定符匹配前面的元素一次或多次, 等效于 {1,}. + 是贪婪限定符, 对应的惰性限定符是 +?.

例如, 正则表达式 \ban+\w*?\b 尝试匹配以字母 a 开头且后跟字母 n 的一个或多个实例的完整单词.

下面示例演示正则表达式匹配单词 an、annual、announcement 和 antique, 但不匹配 autumn 和 all.

字符串: Autumn is a great time for an annual announcement to all antique collectors.

表达式: \ban+\w*?\b

匹配结果(标志 3):
[0]an
[1]annual
[2]announcement
[3]antique

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
an+ | 匹配字符 a , 并要求后跟一个或多个字符 n .
\w*? | 匹配单词字符零次或多次, 但次数尽可能少.
\b | 在单词边界处结束.

匹配一次或多次(惰性匹配): +?

+? 限定符可以匹配前导元素一次或多次, 但次数尽可能少. 它是与贪婪限定符 + 对应的惰性部分.

下面示例演示正则表达式 \b\w+?\b 匹配由字边界分隔的一个或多个字符.

字符串: Aa Bb Cc Dd Ee Ff

表达式: \b\w+?\b

匹配结果(标志 3):
[0]Aa
[1]Bb
[2]Cc
[3]Dd
[4]Ee
[5]Ff

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
\w+? | 匹配单词字符零次或多次, 但次数尽可能少.
\b | 在单词边界处结束.


匹配零次或一次: ?

? 限定符匹配前面的元素零次或一次. 等效于 {0,1}. ? 是贪婪限定符, 对应的惰性限定符是 ??.

例如正则表达式 \ban?\b 尝试匹配以字母 a 开头且后跟字母 n 的零个或一个实例的完整单词. 换言之, 它尝试匹配单词 a 和 an.

下面示例演示此正则表达式:

字符串: An amiable animal with a large snount and an animated nose.

表达式: (?i)\ban?\b

匹配结果(标志 3):
[0]An
[1]a
[2]an

表达式分析:

模式 | 说明
(?i) | 开始不区分大小写的匹配 . 否则匹配不完整 .
\b | 在单词边界处开始.
an? | 匹配后跟零或一个 n 字符的 a .
\b | 在单词边界处结束.

匹配零次或一次(惰性匹配): ??

?? 限定符可以匹配前导元素零次或一次, 但次数尽可能少. 它是与贪婪限定符 ? 对应的惰性部分.

例如正则表达式 ^\s*(System.)??Console.Write(Line)??\(?? 尝试匹配 "Console.Write" 或者 "Console.WriteLine" 字符串. 字符串还可以在“Console”前包含“System." ”, 它后面可以跟着左括号. 该字符串必须位于一行的开头, 不过它的前面可以有空白. 下面的示例演示了此正则表达式:

字符串:
System.Console.WriteLine(\"Hello!\")
Console.Write(\"Hello!\")
Console.WriteLine(\"Hello!\")
Console.ReadLine()
Console.WriteLine

表达式: (?m)^\s*(System.)??Console.Write(Line)??\(??

匹配结果(标志 4):
[0]=> [0]System.Console.Write
[1]=> [0]Console.Write
[2]=> [0]Console.Write
[3]=> [0]Console.Write

表达式分析:

模式 | 说明
(?m) | 激活多行选项 . 使 ^ 能自动连续匹配下一行的开头 , 否则正则表达式只能匹配第一行的文本 .
^ | 匹配输入字符串的开始部分.
\s* | 匹配零个或多个空白字符.
(System.)?? | 匹配字符串 System. 的零个或一个匹配项.
Console.Write | 匹配字符串 Console.Write .
(Line)?? | 匹配字符串 Line 零次或一次.
\(?? | 转义左括号匹配本身. 匹配左括号的零个或一个匹配项


精确匹配 x 次: {x}

{x} 限定符准确匹配前面的元素 x 次, 其中 x 是任何正整数. {x} 是贪婪限定符, 对应的惰性限定符是 {x}?.

下面示例的正则表达式尝试匹配如下字符串: 先是一个字边界, 然后是一个或多个十进制数字, 后面再跟 3 个十进制数字, 最后又是一个字边界.

字符串: Sales totaled 103,524 million in January,106,971 million in February, but only 943 million in March.

表达式: \b\d+\,\d{3}\b

匹配结果(标志 3):
[0]103,524
[1]106,971

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
\d+ | 匹配一个或多个十进制数字.
\, | 匹配逗号字符, 转义逗号字符 .
\d{3} | 匹配三个十进制数字.
\b | 在单词边界处结束.

精确匹配 x 次(惰性匹配): {x}?

{x}? 限定符准确匹配前面的元素 x 次, 其中 x 是任何正整数. 这是贪婪限定符 {x} 对应的惰性部分.

下面示例的正则表达式标识网站地址. 请注意它与 www.microsoft.com 和 msdn.microsoft.com 相匹配, 但与 mywebsite 或 mycompany.com 不匹配.

字符串: www.microsoft.com msdn.microsoft.com mywebsite mycompany.com

表达式: \b(\w{3,}?\.){2}?\w{3,}?\b

匹配结果(标志 4):
[0]=> [0]www.microsoft.com
[1]=> [0]msdn.microsoft.com

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
(\w{3,}?\.) | 至少匹配 3 个字字符, 但字符尽可能少, 后跟圆点或句点字符. 这是第一个捕获组. \. 转义句点匹配本身 .
{2}? | 匹配第一个组的模式两次, 但次数尽可能少.
\w{3,}? | 至少匹配 3 个字字符, 但字符尽可能少.
\b | 在单词边界处结束.


至少匹配 x 次: {x,}

{x,} 限定符匹配前面的元素至少 x 次，其中 x 是任何正整数. {x,} 是贪婪限定符, 对应的惰性限定符是 {x}?.

下面示例的正则表达式尝试匹配如下字符串: 先是一个字边界, 然后是至少 2 个数字, 然后再跟一个字边界和一个非数字字符.
该正则表达式不能匹配短语 7 days , 原因是该短语只包含一个十进制数字; 但该表达式可成功匹配短语 10 weeks 和 300 years .

字符串: 7 days, 10 weeks, 300 years

表达式: \b\d{2,}\b\D+

匹配结果(标志 3):
[0]10 weeks,
[1]300 years

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
\d{2,} | 匹配至少两位十进制数字.
\b | 与字边界匹配.
\D+ | 匹配至少一个非十进制数字.

至少匹配 x 次(惰性匹配): {x,}?

{x,}? 限定符匹配前面的元素至少 x 次, 其中 x 是任何正整数, 但是次数尽可能少. 它是与贪婪限定符 {x,} 对应的惰性部分.

实例请参阅量词限定符的 {x}? 限定符的示例.


匹配 x 到 y 次: {x,y}

{x,y} 限定符匹配前面的元素至少 x 次, 但不超过 y 次，其中 x 和 有为整数. {x,y} 是贪婪限定符, 对应的惰性限定符是 {n,m}?.

下面示例正则表达式 (00\s){2,4} 尝试匹配两个相连的数字 0 和一个紧随的空格, 且匹配 2 到 4 个实例.
注意输入字符串可匹配 (00\s) 的有 5 处, 但开头的子字符串 0x00 FF 部分不符合 {2,4} 的要求, 与该正则表达式模式不匹配:

字符串: 0x00 FF 00 00 18 17 FF 00 00 00 21 00 00 00 00 00

表达式: (00\s){2,4}

匹配结果(标志 4):
[0]=> [0]00 00 从位置 8 开始匹配
[1]=> [0]00 00 00 从位置 23 开始匹配
[2]=> [0]00 00 00 00 从位置 35 开始匹配

表达式分析:

模式 | 说明
(00\s) | 匹配两个相连的数字 0 和一个紧随的空格.
{2,4} | 匹配 2 到 4 个实例.

匹配 x 到 y 次(惰性匹配): {x,y}?

{x,y}? 限定匹配前面元素最少 x 次, 最多 y 次, 其中 x 和 y 为正整数, 但是次数尽可能少. 它是贪婪限定符 {x,y} 对应的惰性部分.

下面示例的正则表达式限制匹配标点符号之前包含 1 到 10 个单词的句子. 字符串中黑色字体句子包含 18 个单词, 不符合 {1,10}? 的要求, 不在匹配范围内.

字符串:
Hi. I am writing a short note.
Its purpose is to test a regular expression that attempts to find sentences with ten or fewer words.
Most sentences in this note are short.

表达式: \b[A-Z](\w*\s*){1,10}?[.!?]

匹配结果(标志 4):
[0]=> [0]Hi.
[1]=> [0]I am writing a short note.
[2]=> [0]Most sentences in this note are short.

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
[A-Z] | 匹配一个 A 到 Z 的大写字符.
(\w*?\s*) | 匹配零个或多个单词字符, 后跟一个或多个空白字符. 这是第一个捕获组.
{1,10}? | 匹配上一个模式最少 1 次, 最多 10 次, 但次数尽可能少. 在标点符号前 , 最少一个单词 , 最多 10 的单词 .
[.!?] | 匹配标点字符 . ! 或 ? 中的任何一个.


贪婪限定符与惰性限定符

限定符有两种版本:

• 贪婪版本. 贪婪限定符尝试尽可能多地匹配元素.

• 非贪婪(惰性) 版本. 贪婪限定符尝试尽可能少地匹配元素. 只需添加 ? 便可以将贪婪限定符转换为惰性限定符.

举例一个简单的正则表达式, 旨在从信用卡号之类的数字串中提取最后四位数. 使用 * 贪婪限定符的正则表达式版本为 \b.*([0-9]{4})\b.

但如果输入字符串包含两组数字, 则此正则表达式只与第二组数字的最后四位数匹配:

字符串: 1112223333 3992991999

表达式: \b.*([0-9]{4})\b

匹配结果(标志 3): [0]1999

该正则表达式未能匹配第一个卡号, 因为 * 限定符尝试在整个字符串中尽可能多地匹配前面的元素, 因此它在字符串的末尾找到了匹配项.

可以使用 *? 惰性限定符从两组号码提取数字, 如下面的示例匹配的数字:

字符串: 同上例.

表达式: \b.*?([0-9]{4})\b

匹配结果(标志 3): [0]3333 [1]1999

在大多数情况下, 带有贪婪限定符和惰性限定符的正则表达式将返回相同的匹配项. 在与元字符 . (匹配任何字符)一起使用时, 它们多数情况下会返回不同的结果.

限定符和空匹配

限定符 *, +,和 {n,m} 以及它们的贪婪限定符在找到最小捕获数后遇到空匹配则不再重复. 此规则会阻止限定符在可能的组捕获最大数目为无限大或接近无限大时进入空子表达式匹配的无限循环.

例如下面示例调用正则表达式模式 (a?)* 的结果, 将匹配零个或一个 a 字符零次或多次. 请注意, 单个捕获组捕获每个 a 以及空匹配, 但没有第二个空匹配, 因为第一个空匹配导致限定翻译停止重复.

字符串: aaabbb
表达式: (a?)*
匹配结果(标志 2): [0]aaa

要查看定义最小和最大捕获数与定义固定捕获数的捕获组之间的实际差异, 请考虑正则表达式模式 (a\1|(?(1)\1)){0,2} 和 (a\1|(?(1)\1)){2}. 这两个正则表达式都包含一个捕获组, 如下表中所定义:

模式 | 说明
(a\1 | 随着第一次捕获组的值匹配 a ……
(?(1) | … 或测试是否已定义第一个捕获组. (请注意, (?(1) 构造不定义捕获组.)
\1)) | 如果第一个捕获分组存在, 则与其值相匹配; 如果分组不存在, 则分组将与 空字符相匹配.

表达式 (a\1|(?(1)\1)){0,2} 试图匹配此模式 0 至 2 次, 而表达式 (a\1|(?(1)\1)){2} 则确定为 2 次. 由于第一个模式在第一次捕获空匹配时达到其最小捕获量, 因此它绝不会重复尝试匹配 a\1; {0,2} 限定符只允许在最后的迭代中存在空匹配. 与之相反, 第二个常规表达式 (a\1|(?(1)\1)){2} 与 a 匹配, 因为它会再一次计算 a\1; 最小迭代次数为 2, 可强制引擎在空匹配后重复.

匹配次数的贪婪与非贪婪

在使用限定符时, 有几种表示方法可以使同一个表达式能够匹配不同的次数, 具体匹配的次数随被匹配的字符串而定.
这种重复匹配不定次数的表达式在匹配过程中, 总是尽可能多的匹配.

贪婪模式:

贪婪限定符: {m,n}, {m,}, ?, *, +. 贪婪限定符首先尝试匹配最大数量的重复.

针对文本 dxxxdxxxd 举例如下:

表达式: (d)(\w+)

匹配结果(标志 2):
[0]dxxxdxxxd
[1]d
[2]xxxdxxxd

表达式分析:

模式 | 说明
(d) | 捕获组 1 . 匹配文本开头字符 d
(\w+) | 捕获组 2 . \w+ 将匹配第一个 d 之后的所有字符 xxxdxxxd .

表达式: (d)(\w+)(d)

匹配结果(标志 2):
[0]dxxxdxxxd
[1]d
[2]xxxdxxx
[3]d

表达式分析:

模式 | 说明
(d) | 捕获组 1 . 匹配文本开头字符 d .
(\w+) | 捕获组 2 . \w+ 将匹配第一个和最后一个 d 之间的所有字符. 虽然 \w+ 也能够匹配最后一个 d , 但是为了使整个表达式匹配成功, \w+ 可以 "让出" 它本来能够匹配的最后一个 d .
(d) | 捕获组 3 . 匹配文本最后字符 d .

由此可见, \w+ 在匹配的时候, 总是尽可能多的匹配符合它规则的字符. 虽然第二个举例中, 它没有匹配最后一个 d , 但那也是为了让整个表达式能够匹配成功.
同理, 带 * 和 {m,n} 的表达式都是尽可能地多匹配, 带 ? 的表达式在可匹配可不匹配的时候, 也是尽可能的 "要匹配". 这种匹配原则就叫作贪婪模式.

非贪婪模式:

懒惰限定符: ??, *?, +?, {n,m}? . 这些限定符指示回溯引擎首先搜索最少数量的重复.

在限定符后再加上一个 ? 号, 则可以使匹配次数不定的表达式尽可能少的匹配, 使可匹配可不匹配的表达式, 尽可能的 "不匹配".
这种匹配原则叫作非贪婪模式, 也叫作 "勉强" 模式. 如果少匹配就会导致整个表达式匹配失败的时候, 与贪婪模式类似, 非贪婪模式会最小限度的再匹配一些, 以使整个表达式匹配成功.

针对文本 dxxxdxxxd 举例如下:

表达式: (d)(\w+?)

匹配结果(标志 2):
[0]dx
[1]d
[2]x

表达式分析:

模式 | 说明
(d) | 捕获组 1 . 匹配文本开头字符 d .
(\w+?) | 捕获组 2 . 将尽可能少的匹配第一个 d 之后的字符, 结果 \w+? 只匹配了一个 x .

表达式: (d)(\w+?)(d)

匹配结果(标志 2):
[0]dxxxd
[1]d
[2]xxx
[3]d

表达式分析:

模式 | 说明
(d) | 捕获组 1 . 匹配文本开头字符 d .
(\w+?) | 捕获组 2. \w+? 不得不只匹配 "xxx" 才可以让后边的 d 匹配, 从而使整个表达式匹配成功. 因此结果是: \w+? 匹配 xxx .
(d) | 捕获组 3 . 匹配文本最后字符 d .

正则表达式 .+(\d+)\. 包含贪婪限定符 .+ , 这使正则表达式引擎仅捕获该数字的最后一位数.
相比之下, 正则表达式 .+?(\d+)\. 包含惰性限定符 .+? , 这使正则表达式引擎捕获整个数字.

用以上两个表达式分别测试字符串: This sentence ends with the number 107325.

贪婪模式 .+(\d+)\. 匹配数字 5. 因为任意字符 . 的贪婪模式, 数字 5 前面的所有字符已被 .+ 捕获, 所有 \d+ 只能匹配剩下的数字字符 5.

惰性模式 .+?(\d+)\. 匹配整个数字 107325.

此正则表达式的贪婪版本和惰性版本的模式定义如下表所示:

模式 | 说明
.+ | 贪婪模式. 匹配任意字符的至少一个匹配项, 无上限. 这会使正则表达式引擎先匹配整个字符串, 然后根据需要进行回溯以匹配模式的其余部分.
.+? | 惰性模式. 匹配任意字符的至少一个匹配项(尽可能少地匹配).
(\d+) | 匹配在句点前面的至少一个数字字符, 无上限. 并将其分配给第一个捕获组.
\. | 匹配句点.


正则表达式选项

默认正则表达式模式文本字符的匹配是区分大小写的, 正则表达式模式中的空白将被解释为空白字符, 并且正则表达式中的捕获组通过隐式和显式命名.

可通过指定正则表达式选项修改正则表达式的这些默认行为.

PCRE 模式可以包含选项, 这些选项包含在 (? ) 序列中. 选项可以组合在一起: (?imx) . 选项后跟随一个连字符表示否定: (?im-sx) .

组集合外部的选项将影响剩余模式. 组集合内部的选项则仅影响本组. 字符组 [...] 内部的选项将失去其特殊含义, 仅代表它们本身.

选项构造并非捕获组. 即尽管子表达式捕获的字符串任意部分包含在匹配中, 但不会包含在捕获的组中.

下面为 AutoIt 帮助 StringRegExp() 文档页描述的选项列表, 点击选项符号查看详细描述:

选项 | 说明
(?i) | 使用不区分大小写的匹配.
(?m) | 使用多行模式, 其中 ^ 和 $ 匹配每行的开头和末尾(不是输入字符串的开头和末尾).
(?s) | 使用单行模式, 其中的句号 . 匹配每个字符(而不是除了 \n 以外的每个字符).
(?U) | 从该点开始量词变得懒惰(非贪婪). 这是 AutoIt 帮助文档的描述, 未找到相关资料.
(?x) | 从模式中排除保留的空白并启用编号符号 (#) 模式后跟的注释. 模式之间的无意义空白使正则表达式有更好的可读性.
(*UCP) | Unicode 类别属性(UCP)支持, 它允许大多数人类语言的细致处理.
(?# 注释文本 ) | 用于说明正则表达式的作用, 意义. 如果出现在子表达式的后面, 则仅对该子表达式作出说明.

如何指定正则表达式的选项

可以用下面 2 种方法之一指定正则表达式的选项:

1 . 通过语法 (?选项组合) 在正则表达式模式中应用内联选项.

以下示例中的正则表达式使用分组构造中的内联选项, 以启用不区分大小写的匹配, 和识别所有以字母 “d” 开头的单词时忽略模式中的空白.

字符串: Dogs are decidedly good pets.

表达式: (?ix) d \w+ \s

匹配结果(标志 3 ):
[0]Dogs
[1]decidedly

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
(?ix: d \w+) | 使用 (?i 不区分大小写的匹配, 并 x 忽略此模式中的白色空间, 匹配后跟一个或多个单词字符的 “d”.
\s | 与空白字符匹配.

2 . 通过语法(选项组行:子表达式)在正则表达式模式的特定分组构造中应用内联选项. 一个选项前面没有符号用于启用该选项 ; 一个选项前面的减号用于禁用该选项.

例如, 内联构造 (?ix-ms) 将启用不区分大小写, 和忽略表达式中的空格, 同时禁用多行和单行模式.

无论选项是启用还是禁用, ? 都是所需语言构造语法的固定部分. 减号不能紧跟在 ? 后面, 否则表示禁用所有选项 .

字符串: Dogs are decidedly good pets.

表达式 2 : \b(?x-i: d \w+)\s

匹配结果(标志 3): [0]decidedly

正则表达式的默认选项

从左到右在输入字符串中匹配正则表达式模式.

比较区分大小写.

^ 和 $ 元素匹配输入字符串的开头和结尾.

. 句点元素匹配除 \n(换行符) 之外的每个字符匹配.

正则表达式模式中的任意空白均解释为文本空白字符。

将模式与输入字符串进行比较时将使用当前区域性的约定.

正则表达式模式中的捕获组可以是隐式的, 也可以是显式的.


不区分大小写的匹配: (?i)

选项 (?i) 提供不区分大小写的匹配方式. 默认使用当前区域的大小写约定.

下面示例模式定义匹配以 "the" 开头的所有单词的正则表达式模式 \bthe\w*\b .

字符串: The man then told them about that event.

表达式: \bthe\w*\b

匹配结果(标志 3):
[0]then
[1]them
因为正则表达式默认使用区分大小写的比较, 因此该模式不匹配 "The" 开头的单词.

下面的示例修改了上一示例中的正则表达式模式, 使用内联选项而不单是选项参数来提供不区分大小写的比较.

表达式: \b(?i:t)he\w*\b

匹配结果(标志 3):
[0]The
[1]then
[2]them

表达式分析:

模式 | 说明
\b | 在单词字符的边界开始匹配.
(?i:t) | 定义字符 t 的匹配不区分大小写. 因为选项构造在模式的开始处出现, 所以选项模式将应用于整个正则表达式.
he | 匹配文本字符 he
\w* | 匹配 0 个或更多个单词字符.
\b | 在单词字符的边界结束匹配.


单行模式: (?s)

选项导致正则表达式引擎将输入字符串视为由单行组成. 它通过更改句号 . 语言元素的行为, 使其与每个字符匹配, 而不是与除换行符 \n 之外的每个字符匹配来执行此操作.

下面的示例演示使用单行模式 (?s) 选项时如何更改 . 的行为. 正则表达式 ^.+ 在字符串开头开始并匹配每个字符.

默认匹配到第一行的结尾结束; 正则表达式模式匹配回车符 \r 但不匹配换行符 \n , 因此匹配仅返回第一行的文本.

但 (?s) 选项能将整个输入字符串解释为单行, 因此它匹配输入字符串中的每个字符, 包括换行符 \n .

字符串:
This is one line and
this is the second.

表达式: (?s)^.+

匹配结果(标志 1, 或2, 或 3):
[0]This is one line and
this is the second.


多行模式: (?m)

选项使正则表达式引擎能够处理由多个行组成的输入字符串. 它更改了 ^ 和 $ 语言元素的解释, 以使它们分别与每行的开头和结尾匹配, 而不只是与输入字符串的开头和结尾匹配.

默认情况下, $ 仅与输入字符串的末尾匹配. 如果指定了 (?m) 选项, 它将与换行符 (\n) 或输入字符串的末尾匹配. 但并不与回车符/换行符的组合 \如\n 匹配. 若要成功匹配它们, 使用子表达式 \r?$ 替代 $.

下面的示例提取投手的姓名和分数. 测试两个匹配方法.

第 1 方法调用正则表达式 ^(\w+)\s(\d+)$, 且没有设置任何选项. 因为正则表达式引擎与输入模式及输入字符串的开头和结尾均不匹配, 因此没有找到匹配.

第 2 方法调用正则表达式更改为 (?m)^(\w+)\s(\d+)$, 选项设置为 (?m) , 姓名和分数成功匹配.

字符串:
Joe 164
Sam 208
Allison 211
Gwen 171

表达式: (?m)^(\w+)\s(\d+)$

匹配结果(标志 4):
[0]=> [0]Joe 164
[1]=> [0]Sam 208
[2]=> [0]Allison 211
[3]=> [0]Gwen 171

表达式分析:

模式 | 说明
(?m) | 匹配多个回车符. 否则正则表达式将提示输入字符串没有匹配项.
^ | 因为选项 (?m) 的存在, ^ 可以从每行的开头开始匹配.
(\w+) | 匹配一个或多个单词字符. 这是第一个捕获组.
\s | 与空白字符匹配.
(\d+) | 匹配一个或多个十进制数字. 这是第二个捕获组.
$ | 因为选项 (?m) 的存在, $ 可以从每行的尾部结束一轮匹配.


忽略正则表达式的内部空白: (?x)

默认正则表达式模式中的空白非常重要; 它会强制正则表达式引擎与输入字符串中的空白字符相匹配. 因此, 正则表达式 \b\w+\s 和 "\b\w+ "(+ 号后留有一个空格)是大致等效的正则表达式. 此外, 正则表达式模式中出现编号符号 (#) 时, 它被解释为匹配 # 的原义字符.

选项 (?x) 可以更改此默认行为, 如下所示:

正则表达式模式中的非转义的空白将被忽略.

编号符号 (#) 被解释为注释文本的开头, 而不是原义字符. 正则表达式模式中的所有文本, 从 # 字符到字符串的结尾都解释为注释文本.

但在下列情况下, 不会忽略正则表达式中的空白字符, 即使使用 (?x) 选项也是如此:

始终按原义解释字符内的空格. 例如, 正则表达式的字符组模式 [ .,;:] 匹配任意单个空白字符, 句号, 逗号, 分号或冒号.

加括号的限定符内不允许有空格, 如 {n}、{n,} 和 {n,m} . 例如 \d{1. 3} , 因为它包含一个空白字符, 所以正则表达式模式与任何从 1 到 3 位数的数字序列都不匹配.

引入语言元素的字符序列内不允许有空格. 例如：

语言元素 (?:子表达式) 表示非捕获组, 并且该元素的 (?: 部分不能嵌入空格. 模式 (? :子表达式) 在运行时引发参数异常, 因为正则表达式引擎不能分析该模式, 且模式 ( ?:子表达式) 与子表达式不匹配.

语言元素 \p{name} 表示一个 Unicode 类别或命名块, 它不能在元素的 \p{ 部分中嵌入空格. 如果你包括了空格, 则该元素会在运行时引发参数异常.

启用 (?x) 选项有助于简化通常很难分析和理解的正则表达式. 它提高了正则表达式的可读性.

下面的示例使用选项 (?x) 来忽略模式中空白.

字符串: This is the first sentence! Is it the beginning of a literary masterpiece? I think not. Instead, it is a nonsensical paragraph.

表达式: (?x)\b \(? ( (?>\w+) ,?\s? )+ [\.!?] \)? # 匹配整个输入文本字符串

匹配结果(标志 4):
[0]=> [0]This is the first sentence!
[0]=> [1]sentence
[1]=> [0]Is it the beginning of a literary masterpiece?
[1]=> [1]masterpiece
[2]=> [0]I think not.
[2]=> [1]not
[3]=> [0]Instead, it is a nonsensical paragraph.
[3]=> [1]paragraph

表达式分析:

模式 | 子模式 | 说明
(?x) |  | 忽略正则表达式中包含的空白字符.
\b |  | 在单词边界处开始.
\(? |  | 匹配左括号 “(” 的零或一个匹配项. 源字符串没有 ( 符号, 但测试添加一个 ( 符号, 不能返回匹配 ?
((?>\w+),?\s?)+ |  | 一次或多次匹配一个或多个单词字符, 零或一个逗号以及零或一个空白字符的组合
 | (?>\w+),? | 匹配一个或多个单词字符, 后跟零或一个逗号. 当匹配单词字符不回溯
 | \s? | 匹配零个或一个空白字符.
[\.!?]\)? |  | 与后无右括号或后跟一个右括号 “)” 的三个标点符号 . ! ? 匹配

下面的示例使用 i 以及 x 选项启用区分大小写, 并忽略正则表达式模式中间的空白.

字符串: double dare double Double a Drooling dog The Dreaded Deep

表达式: \b(D\w+)(?ix) \s (d\w+) \b

匹配结果(标志 1): [0]Drooling [1]dog

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
(D\w+) | 匹配大写字母 D 开头的一个或多个单词字符. 这是第一个捕获组.
(?ix) | 此后, 进行不区分大小写的比较 , 并忽略正则表达式模式中的空白 .
\s | 与空白字符匹配.
(d\w+) | 匹配小写字母 d 开头的一个或多个单词字符.
\b | 在单词边界处结束.

以下示例中的正则表达式 \b(?ix: d \w+)\s 使用分组构造中的内联选项, 以启用不区分大小写的匹配, 并在识别所有以字母 d 开头的单词时忽略模式中的空白.

字符串: Dogs are decidedly good pets.

表达式: \b(?ix: d \w+)\s

匹配结果(标志 3):
[0]Dogs
[1]decidedly

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
(?ix: d \w+) | 使用不区分大小写的匹配并忽略此模式中的空白空间, 匹配一个或多个以字符 d 开头的单词字符 .
\s | 匹配一个空白符, 并结束一轮匹配过程 .


Unicode 类别属性(UCP)支持

AutoIt 使用 PCRE 引擎(Perl 兼容的正则表达式), 是最全面的开源引擎. 这个引擎包括 Unicode 类别属性(UCP)支持, 它允许大多数人类语言的细致处理. 然而, 为了维持与以前版本的兼容性, 并保持在其最佳的匹配速度, 默认不启用 UCP 支持. 您可以通过在表达式前添加选项 (*UCP) 启用它. 启用时, UCP 设置将更改正则表达式元素的匹配扩展.

默认正则表达式模式与输入文本匹配时, 正则表达式引擎会采用规范行为. 但是可以指示正则表达式引擎通过指定 (*UCP) 选项使用 UCP 匹配行为.

注意: (*UCP) 与\p{} 同属 Unicode 类别属性支持, 但使用方法是不一样的!

下面示例规范行为和 UCP 匹配行为对同一输入字符串的不同品牌结果, 定义规范匹配和 UCP 匹配的 2 个表达式, 该表达式与后跟空白字符的单词匹配. 输入由两个字符串组成的输入, 其中一个字符串使用拉丁字符集, 另一个则使用西里尔字符集:

字符串: целый мир , the whole world

规范匹配表达式: \b(\w+\s*)+

匹配结果(标志 4): 仅匹配由拉丁字符组成的语句.
[0]=> [0]the whole world

UCP 匹配表达式: (*UCP)\b(\w+\s*)+

匹配结果(标志 4)
[0]=> [0]целый мир
[1]=> [0]the whole world
同时匹配西里尔字符和拉丁字符组成的语句.


正则表达式的内联注释和行尾注释: (?# 注释文本)

编号符号 (#) 标记模式的注释, 从正则表达式模式结尾的非转义 # 字符开始, 并继续到行的末尾, 描述整个正则表达式的作用意义;

当 (?# 注释文本) 出现在子表达式后面则为内联注释, 描述子表达式的作用意义.

下面的示例阐释内联注释和行尾注释的构造. 它确定字符串是否是一个包含至少一个格式项的复合格式字符串.

字符串: "{0,-3:F}"

表达式: \{\d+(,-*\d+)*(\:\w{1,4}?)*(?# 不区分大小写比较)\}(?x) # 查找一个合成格式项.

匹配结果(标志 3):
[0]"{0,-3:F}"
[1],-3
[2]:F

表达式分析:

模式 | 说明
\{ | 转义字符 { 为字符本身原意 . 匹配左括号 {
\d+ | 匹配一个或多个十进制数字.
(,-*\d+)* | 匹配逗号的 0 个或一个匹配项, 后跟可选负号, 负号后跟一个或多个十进制数.
(\:\w{1,4}?)* | 转义冒号字符 : 为字符本身原意 . 匹配冒号的 0 个或一个匹配项, 冒号后跟一至四个空白字符, 但空白字符尽可能少.
(?# 不区分大小写比较) | 内联注释. 它不影响模式匹配行为.
\} | 转义字符 } 为字符本身原意 . 匹配右括号 }
(?x) | 启用忽略模式空白选项, 以便识别行尾注释文本. 或替换为使用 (?# ... ) 效果相同 .
# 查找一个合成格式项. | 行尾注释文本. 它不影响模式的匹配行为.

下面示例两个内嵌批注添加到正则表达式, 说明比较是否区分大小写:

字符串: double dare double Double a Drooling dog The Dreaded Deep

表达式: \b((?# 区分大小写的比较)D\w+)\s(?ix)((?#不区分大小写的比较)d \w+ )\b

匹配结果(标志 2):
[0]Drooling dog
[1]Drooling
[2]dog

表达式分析:

模式 | 说明
\b | 在单词边界处开始
(?# 区分大小写的比较) | 注释. 它不影响模式匹配行为. 说明在单词边界处开始的匹配区分大小写 .
D\w+) | 匹配后跟一个或多个大写字符 D .这是第一个捕获组.
\s | 与空白字符匹配.
(?ix) | 此后,进行不区分大小写的比较, 并忽略正则表达式模式中的空白
(?#不区分大小写的比较) | 注释. 它不影响模式匹配行为. 说明在此处开始的匹配不区分大小写 .
d\w+) | 匹配大写或小写字符 d 后跟一个或多个字符. 这是第二个捕获组.
\b | 在单词边界处开始.


正则表达式中的分组捕获构造: (...)

正则表达式支持许多分组构造, 允许你将正则表达式模式分组为一个或多个子表达式. 最常用的分组构造为 (子表达式) 定义编号的捕获组和 (?<名称>子表达式) 定义命名的捕获组.
分组构造是创建反向引用和定义要应用限定符的子表达式时所必需的. 应用限定符的捕获组, 正则表达式以后不会再引用这些子表达式捕获的组.

分组构造描述正则表达式的子表达式, 用于捕获输入字符串的子字符串. 你可以使用分组构造来完成下列任务：

分组子表达式匹配输入字符串中重复的字符串.

将限定符应用于拥有多个正则表达式语言元素的子表达式. 有关限定符的详细信息参阅正则表达式中的限定符.

下表列出正则表达式引擎支持的分组构造, 并指示它们是捕获还是非捕获:

分组构造 | 捕获或非捕获
普通捕获组 (子表达式) | 捕获
命名捕获组 (?<name>子表达式) 或 (?'name' 子表达式) | 捕获
平衡捕获组 | 捕获 ( 似乎 AutoIt 不支持, 因此没有收录相关描述和示例 )
非捕获组 (?:子表达式) | 非捕获
分组选项 | 非捕获
正预测先行断言 (?=断言模式) | 非捕获
正回顾后发断言 (?<=断言模式) | 非捕获
负回顾后发断言 (?<!断言模式) | 非捕获
负预测先行断言 (?!断言模式) | 非捕获
非回溯子表达式 (?>子表达式 ) | 非捕获
条件判断捕获组 (?(?=条件模式)yes|no) | 捕获
反向引用 \编号 \k<name> |
可选构造 (子模式|子模式) | 捕获
捕获组应用限定符 | 捕获
普通组与命名组混合编号规则 |


普通捕获组: (子表达式)

子表达式为任何有效正则表达式模式. 捕获组编号按正则表达式中左括号从左到右的顺序从 1 开始自动编号. 编号为 0 的捕获是整个正则表达式模式匹配的文本.

正则表达式可以反向引用普通捕获组. 语法 \0 - \9 , 在同一正则表达式中引用匹配的子表达式, 其中数字是未命名捕获组的编号.

普通捕获组返回一个组收集对象, 该对象包含多个组对象, 这些对象表示捕获组的单个匹配项. 集合中的第一个组对象(对应数组索引 [0])表示整个表达式的匹配项. 此对象后面的每个对象均表示一个捕获组的结果.

可以使用组属性检索集合中的各个组收集的项对象. 在集合中按未命名组的序号位置来检索未命名组, 也可以按命名组的名称或序号位置来检索命名组.

未命名捕获组将首先在集合中显示, 并将按照未命名捕获在正则表达式模式中出现的顺序从左至右对它们进行索引. 在对未命名捕获进行索引后, 再将按照命名捕获组在正则表达式模式中出现的顺序从左至右对它们进行索引.

若要确定在特定的正则表达式匹配方法返回的集合中哪些编号的组可用, 可以调用实例的组编号. 若要确定集合中哪些命名的组可用, 可以调用实例的组名称. 这两种方法都对分析任何正则表达式找到匹配的通用程序特别有用.

组收集项可以按索引(对于命名组, 可以按名称)访问各个组对象.

下面的示例定义一个正则表达式, 该表达式使用分组构造捕获日期的年, 月, 日部分.

字符串: Born: July 28, 1989

表达式: \b(\w+)\s(\d{1,2}),\s(\d{4})\b

匹配结果(标志 2):
[0]July 28, 1989
[1]July
[2]28
[3]1989

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
(\w+) | 匹配一个或多个单词字符. 这是第一个捕获组. 对应数组索引 [1] , 月份
\s | 与空白字符匹配
(\d{1,2}) | 匹配一个或两个十进制数字. 这是第二个捕获组. 对应数组索引 [2] 日数
, | 匹配逗号
\s | 与空白字符匹配
(\d{4}) | 匹配四个十进制数字. 这是第三个捕获组. 对应数组索引 [3] 年号
\b | 在单词边界处结束匹配

下面示例使用嵌套的分组构造来将子字符串捕获到组中. 正则表达式将子字符串 ab 分配给第一个捕获组, 并将子字符串 b 分配给第二个捕获组.

字符串: abc

表达式: (a(b))c

匹配结果(标志 2): [0]abc [1]ab [2]b

表达式分析:

模式 | 子模式 | 说明
(a(b)) |  | 匹配字符 ab . 这是第一捕获组. 对应 [1].
 | (b) | 匹配字符 b . 这是第二捕获组. 对应 [2].
c |  | 匹配字符 c .

以下示例匹配文本中重复单词的正则表达式. 正则表达式模式的两个捕获组( 对应 [0]=> [0]that that 和 [1]=> [0]the the )表示重复单词的两个实例.

字符串: He said that that was the the correct answer.

表达式: (\w+)\s(\1)\W

匹配结果(标志 4):
[0]=> [0]that that
[0]=> [1]that
[0]=> [2]that
[1]=> [0]the the
[1]=> [1]the
[1]=> [2]the

表达式分析:

模式 | 说明
(\w+) | 匹配一个或多个单词字符. 这是第 1 捕获组
\s | 与空白字符匹配.
(\1) | 与第 1 捕获组捕获中的字符串匹配. 这是第 2 捕获组. 该示例将匹配值指定到捕获组, 以便重复单词的开始位置可从返回数组中检测.
\W | 匹配包括空格和标点符号的一个非单词字符. 这样可以防止正则表达式模式匹配第 1 捕获组单词开头的单词. 防止重复匹配 .

普通捕获组编号规则

编号规则指的是以数字为捕获组进行编号的规则, 在普通捕获组或命名捕获组单独出现的正则表达式中, 编号规则比较清晰,

在普通捕获组与命名捕获组混合出现的正则表达式中, 捕获组的编号规则稍显复杂. 参见普通捕获组与命名捕获组混合编号

需要说明的是, 编号为 0 的捕获组, 指的是整体正则表达式的匹配结果.

如果没有显式为捕获组命名, 即没有使用命名捕获组, 那么需要按数字顺序来访问所有捕获组. 在只有普通捕获组的情况下, 捕获组的编号是按照 "(" 出现的顺序, 从左到右, 从 1 开始进行编号的 .

表达式: (\d{4})-(\d{2}-(\d\d)) 组编号:

上面的正则表达式可以用来匹配格式为 yyyy-MM-dd 的日期, 为了在下表中得以区分, 月和日分别采用了 \d{2} 和 \d\d 这两种写法.

用以上正则表达式匹配字符串: 2016-02-01. 选择标志 4, 测试匹配结果为:

组编号 | 组模式 | 匹配结果
0 | (\d{4})-(\d{2}-(\d\d)) | [0]=> [0]2016-02-01
1 | (\d{4}) | [0]=> [1]2016
2 | (\d{2}-(\d\d)) | [0]=> [2]02-01
3 | (\d\d) | [0]=> [3]01


命名捕获组 : (?<name>子表达式) 或 (?'name' 子表达式)

其中名称是有效的捕获组名称, 名称不得包含任何标点符号字符, 并且不能以数字开头. 而子表达式是任何有效的正则表达式模式.

正则表达式可以反向引用命名捕获组. 语法 \k<名称> , 在同一正则表达式中引用匹配的子表达式, 其中名称是命名捕获组的名称.

命名组可以通过编程方式, 或通过正则表达式语言语法引用已命名的组.

正则表达式 ((?<One>abc)\d+)?(?<Two>xyz)(.*) 按编号和名称产生下表所列捕获组. 编号为 0 的第一个捕获组总是指整个模式的最终匹配结果.

字符串: abc123xyz258gef,

表达式: ((?<One>abc)\d+)?(?<Two>xyz)(.*)

选择标志 4 的匹配结果按编号和名称产生下列捕获组:

数字 | 组名称 | 模式及其捕获内容
0 | 默认名称 0 | ((?<One>abc)\d+)?(?<Two>xyz)(.*) 匹配结果 : [0]=> [0]abc123xyz258gef,
1 | 默认名称 1 | ((?<One>abc)\d+) 匹配结果 : [0]=> [1]abc123
2 | One | (?<One>abc) 匹配结果 : [0]=> [2]abc
3 | Two | (?<Two>xyz) 匹配结果 : [0]=> [3]xyz
4 | 默认名称 4 | (.*) 匹配结果 : [0]=> [4]258gef,

下面示例标识文本字符串中重复的单词, 重复单词紧随的单词. 正则表达式模式定义了两个命名的子表达式: duplicateWord, 它表示重复的单词; 和 nextWord, 它表示重复单词后面跟随的单词.

字符串: He said that that was the the correct answer.

表达式: (?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)

匹配结果(选择标志 3):
[0]that ; 位置 8 开始的重复单词.
[1]was ; 其后紧随的单词.
[2]the ; 位置 22 开始的重复单词.
[3]correct ; 其后紧随的单词.

表达式分析:

模式 | 说明
(?<duplicateWord>\w+) | 匹配一个或多个单词字符. 命名此捕获组名称为 duplicateWord
\s | 与空白字符匹配.
\k<duplicateWord> | 匹配名为 duplicateWord 的捕获组. \k 表示引用先前捕获组的名称.
\W | 匹配包括空格和标点符号的一个非单词字符
(?<nextWord>\w+) | 匹配一个或多个单词字符. 命名此捕获组名称为 nextWord

下面示例的正则表达式 \D+(?<digit1>\d+)\D+(?<digit2>\d+)? 中, 第一个名为 digit1 的组捕获一个或多个数字字符. 第二个名为 digit2 的组捕获一个或多个数字字符的零个或一个匹配项. 如果第二个捕获组成功匹配文本, 则文本的值定义组对象的值. 如果第二个捕获组无法匹配输入字符串, 则最后一个成功匹配的值定义组对象的值.

字符串: abc123def456abc123def

表达式: \D+(?<digit1>\d+)\D+(?<digit2>\d+)?

匹配结果(标志 4):
[0]=> [0]abc123def456
[0]=> [1]123
[0]=> [2]456
[1]=> [0]abc123def
[1]=> [1]123

表达式分析:

模式 | 说明
\D+ | 匹配一个或多个非十进制数字字符
(?<digit1>\d+) | 匹配一个或多个十进制数字字符. 将匹配值分配到 digit1 命名组.
\D+ | 匹配一个或多个非十进制数字字符
(?<digit2>\d+)? | 匹配一个或多个十进制数字字符的 0 个或一个匹配项. 将匹配值分配到 digit2 命名组.

下面的示例使用命名的分组构造, 从包含 “数据分析:值” 格式的数据字符串中捕获子字符串, 正则表达式通过冒号 : 拆分数据:

字符串: Section1:119900

表达式: ^(?<name>\w+):(?<value>\w+)

匹配结果(标志 3):
[0]Section1
[1]119900

表达式分析:

模式 | 说明
^ | 从输入字符串的开头部分开始匹配.
(?<name>\w+) | 匹配一个或多个单词字符. 此捕获组的名称为 name
: | 匹配冒号.
(?<value>\w+) | 匹配一个或多个单词字符. 此捕获组的名称为 value

命名捕获组编号规则

命名捕获组为显式命名, 通过组名可以访问指定的组, 而不需要去一个个的数编号, 同时避免了在正则表达式扩展过程中, 捕获组的增加或减少对引用结果导致的不可控.

不过容易忽略的是, 命名捕获组也参与了编号的, 在只有命名捕获组的情况下, 捕获组的编号也是按照 "(" 出现的顺序, 从左到右, 从 1 开始进行编号的 . 编号为 0 的第一个捕获组总是指整个模式的匹配结果.

例如正则表达式: (?<year>\d{4})-(?<date>\d{2}-(?<date>\d{2}-(?<day>\d\d)) 的组编号如下:

用以上正则表达式匹配字符串: 2016-03-01. 选择标志 4, 测试匹配结果为:

编号 | 命名 | 捕获组 | 匹配内容
0 |  | (?<year>\d{4})-(?<date>\d{2}-(?<day>\d\d)) | [0]=> [0]2016-03-01
1 | year | (?<year>\d{4}) | [0]=> [1]2016
2 | date | (?<date>\d{2}-(?<day>\d\d)) | [0]=> [2]03-01
3 | day | (?<day>\d\d)) | [0]=> [3]01


条件判断捕获组 (?(?=条件模式)yes 模式|no 模式) 或 (?(name)yes 模式|no 模式)

对于(?(?=条件模式)yes|no) , 如果条件表达式 (?=条件模式) 匹配成功, 则匹配 yes 子表达式, 否则匹配 no 子表达式.

对于 (?(name)yes|no) , 如果命名捕获组 name 有捕获, 则匹配 yes 子表达式, 否则匹配 no 子表达式.

如果 条件模式 与可能出现的命名捕获组的组名相同, 为避免混淆, 可以采用 (?(?=条件模式)yes|no) 方式显示声明 条件模式 为子表达式, 而不是捕获组名.

(?(?=条件模式)yes|no) 验证当前位置右侧是否能够匹配 条件模式 , 属于顺序断言结构, 是零宽度的, 所以它只参与判断, 即使匹配成功, 也不会占有字符.

下表录入 AutoIt 帮助 StringRegExp() 函数文档的相关描述:

其中 (条件模式) 可以是任何以下形式:

(n) | 测试捕获组是否与绝对数 n 匹配.
(+n) | 测试捕获组是否与相对数 +n 匹配.
(-n) | 测试捕获组是否与相对数 -n 匹配.
(<name>) | 测试捕获组是否与名称 name 匹配
(R) | 测试捕获组是否发生任何种类的递归.
(Rn) | 测试捕获组最近递归是否为绝对数 n.
(R&name) | 测试捕获组最近递归名称是否为 name.
(DEFINE) | 如果省略 no 子模式, 允许使用其它地方定义的子程序. "(?x) (?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) )" 定义名为 "byte" 的子程序, 匹配一个 IPv4 地址的任何组成部分. 实际地址可由 "\b (?&byte) (\.(?&byte)){3} \b" 匹配.
(assertion) | 断言为正数或负数, 断言为预取或后处理之一.

捕获组的条件判断计算: (?(条件模式)yes| no ) 和 (?(name)yes| no ),

其中条件模式是要匹配的子表达式, name 是捕获组的名称; yes 是当条件模式, 或 name 匹配成功时要匹配的字符串; 而 no 是当条件模式, 或 name 匹配无效时要匹配的子表达式.

此功能允许引擎根据前面的条件模式匹配的结果, 或零宽度断言的结果, 使用多个替换模式进行搜索. 这提供了超越反向引用所允许的, 更为强大的功能.

下面的示例中的正则表达式匹配输入文本中供公用和内部使用的段落. 仅供内部使用的段落以 <PRIVATE> 标记开始.

正则表达式模式 (?m)^(?<Pvt>\<PRIVATE\>\s)?(?(Pvt)((\w+\p{P}?\s)+)|((\w+\p{P}?\s)+))\r?$ 使用条件计算向单独捕获组分配公用和内部使用的段落内容, 然后可以按不同方式处理这些段落.

字符串:
<PRIVATE> This is not for public consumption.
But this is for public consumption.
<PRIVATE> Again, this is confidential. ; 注意: 此句后面需要回车换行 !

匹配结果(标志 3):
[0]<PRIVATE>
[1]This is not for public consumption.
[2]consumption.
[3]
[4]
[5]
[6]But this is for public consumption.
[7]consumption.

[8]<PRIVATE>
[9]Again, this is confidential.
[10]confidential.

表达式分析:

模式 | 说明
(?m) | 使用多行模式, 其中 ^ 和 $ 匹配每行的开头和末尾(不是输入字符串的开头和末尾). 有关更多信息, 请参见单行与多行模式.
^ | 从行的开头开始匹配.
(?<Pvt>\<PRIVATE\>\s)? | 匹配后跟空格字符的字符串 <PRIVATE> 的 0 个或 1 个匹配项. 将匹配项分配给名为 Pvt 的捕获组.
(?(Pvt)((\w+\p{P}?\s)+) | 如果 Pvt 捕获组存在, 则匹配一个或多个以下模式: 一个或多个单词字符, 后跟零个或一个标点分隔符, 再后跟一个空格字符. 将子字符串分配给第一个捕获组.
| | yes 与 no 的子模式分隔符
((\w+\p{P}?\s)+)) | 如果 Pvt 捕获组不存在, 则匹配一个或多个以下模式: 一个或多个单词字符, 后跟零个或一个标点分隔符, 再后跟一个空格字符. 将子字符串分配给第三个捕获组.
\r?$ | 匹配行尾或字符串的结尾.

示例:

字符串: abc

表达式: (?(?=a)\w{2}|\w)

匹配结果(标志 1 或 2): [0]ab

模式 | 说明
(?(?=a)\w{2}|\w) | 条件判断捕获组, 当前位置右侧如果是字符 " a ", 则整体表达式匹配两个 \w , 否则匹配一个 \w
(?(?=a) | 条件表达式, 指定当前位置右侧字符为 a
\w{2} | yes 子表达式, 如果条件成立, 则整体表达式匹配两个 \w ( 2 个字母字符)
|\w) | no 子表达式 , 否则匹配一个 \w (字符串的第 1 个字母字符)

另一示例参阅可选构造中的条件匹配的表达式.


普通捕获组与命名捕获组混合编号规则

当一个正则表达式中, 普通捕获组与命名捕获组混合出现时, 捕获组的编号规则稍显复杂. 对于其中的命名捕获组, 随时都可以通过组名进行访问, 而对于普通捕获组, 则只能通过确定其编号进行访问.

混合方式的捕获组编号, 首先按照普通捕获组中 "(" 出现的先后顺序, 从左到右, 从 1 开始进行编号, 当普通捕获组编号完成后, 再按命名捕获组中 "(" 出现的先后顺序, 从左到右, 接着普通捕获组的编号值继续进行编号.

也就是先忽略命名捕获组, 对普通捕获组进行编号, 当普通捕获组完成编号后, 再对命名捕获组进行编号.

正则表达式: (\d{4})-(?<date>\d{2}-(\d\d))

用以上正则表达式匹配字符串: 2016-02-01. 在 AutoIt 中选择标志 4, 测试匹配结果为:

组编号 | 命名 | 捕获组 | 匹配内容
0 |  | (\d{4})-(?<date>\d{2}-(\d\d)) | [0]=> [0]2016-02-01
1 |  | (\d{4}) | [0]=> [1]2016
3 | date | (?<date>\d{2}-(\d\d)) | [0]=> [2]02-01
2 |  | (\d\d) | [0]=> [3]01


非捕获组: (?:子表达式)

非捕获组不会捕获由子表达式匹配的子字符串, 子表达式为任何有效正则表达式模式. 当限定符应用到捕获组, 如果组捕获的子字符串并非所需时, 通常会使用非捕获组构造.

如果正则表达式包含嵌套的分组构造, 则外部非捕获组构造不适用于内部嵌套组构造.

可以通过以下方式之一使用非捕获组:

使用 (?:子表达式) 语言元素. 此元素可防止应用组中捕获匹配的子字符串. 但它不在任何嵌套的组中禁用子字符串捕获.

在正则表达式模式中禁用所有未命名或隐式捕获. 使用此选项时, 只能捕获使用 (?<name>子表达式) 语言元素定义的命名组匹配的子字符串.

下面示例捕获组与非捕获组的最终匹配结果的区别, 两个正则表达式都用于捕获整个句子:

字符串: This is one sentence. This is another.

捕获组表达式: \b(\w+[;,]?\s?)+[.?!]

匹配结果(标志 4):
[0]=> [0]This is one sentence.
[0]=> [1]sentence
[1]=> [0]This is another.
[1]=> [1]another

查找匹配时, 捕获分组 ([0]=> [0], [1]=> [0]) 和捕获对象 ([0]=> [1] , [1]=> [1]) 都将用捕获内容来填充.
此时对捕获组 (\w+[;,]?\s?) 应用 + 限定符, 从而使得正则表达式模式可与句子中的每个单词匹配. 否则它将匹配句子中的最后一个单词.

当你对子表达式应用限定符, 并且对捕获的单词 ([0]=> [1] , [1]=> [1]) 不感兴趣时, 应禁用组捕获, (?:子表达式) 语言元素可避免捕获你不感兴趣.

非捕获组表达式: \b(?:\w+[;,]?\s?)+[.?!]

匹配结果(标志 4):
[0]=> [0]This is one sentence.
[1]=> [0]This is another.

表达式分析:

模式 | 子模式 | 说明
\b |  | 在单词边界处开始匹配.
(?: |  | 定义 (\w+[;,]?\s?) 为非捕获组 , 不捕获句子字符串中后跟标点符号单词 .
(\w+[;,]?\s?)+ |  | 匹配 1 或多个以下子表达式捕获的组合. 匹配结果用于定义第一个捕获组, 这是必需的, 以便匹配后跟可选标点符号的单词字符, 直至正则表达式引擎到达句子末尾.
 | \w+ | 匹配一个或多个单词字符.
 | [;,]? | 匹配 0 个或 1 个(单词后跟的)逗号, 或分号
 | \s? | 匹配 0 个或 1 个(逗号, 或分号后跟的)空白字符
[.?!] |  | 匹配 1 个句号, 或 1 个问号, 或 1 个感叹号.

下面的示例包括非捕获组的正则表达式. 请注意输出不包含任何已捕获组( 即没有匹配单词的捕获组 ):

字符串: This is a short sentence.

表达式: (?:\b(?:\w+)\W*)+\.

匹配结果(标志 1, 或 2, 或 3, 或 4): This is a short sentence.

正则表达式 (?:\b(?:\w+)\W*)+\. 匹配由句号终止的语句. 因为正则表达式重点在句子, 而不是个别单词, 所以分组构造使用非捕获组模式, 以避免捕获单词字符.

模式 | 子模式 | 说明
(?:\b(?:\w+)\W*)+\. |  | 非捕获组模式. 不将匹配的文本分配给捕获的组. 组内子模式分述如下:
 | (?: | 定义子表达式为非捕获组.
 | \b | 在单词边界处开始匹配.
 | (?:\w+) | 定义表达式为非捕获组. 匹配 1 个或多个单词字符, 不将匹配的文本分配给捕获组.
 | \W* | 匹配 0 个或多个非单词字符.
 | \. | 转义句点字符, 匹配句点本身. 并结束匹配过程 .


正则表达式中的反向引用构造

反向引用为标识字符串中重复字符或子字符串提供方便途径. 例如, 如果输入字符串包含某任意子字符串的多个匹配项, 则可以使用捕获组匹配第一个出现的子字符串, 然后使用反向引用匹配后面出现的子字符串

单独语法用于引用命名的和带编号的捕获组的匹配项替换输入字符串的子字符串. 有关详细信息, 请参阅正则表达式替换.

定义引用编号和已命名的捕获组的单独语言元素. 有关捕获组的详细信息, 请参阅正则表达式中的分组构造.

普通捕获组反向引用: \编号

其中编号是正则表达式中捕获组的序号位置. 例如, \4 匹配第四个捕获组的内容. 如果正则表达式模式中未定义编号, 则将发生分析错误, 并且正则表达式引擎将引发参数异常.

例如,正则表达式 \b(\w+)\s\1 有效, 因为 (\w+) 是表达式中的第一个也是唯一一个捕获组. 另一方面, \b(\w+)\s\2 无效, 并因为不存在捕获组编号 \2 而引发参数异常.

请注意八进制转义代码(如 \16)和使用相同表示法的 \编号 后向引用之间的多义性. 此多义性通过如下方式解决:

1. 表达式 \1 到 \9 总是解释为反向应用, 而不是八进制代码.

2. 如果多位表达式的第一个数字是 8 或 9(如 \80 或 \91), 则该表达式将被解释为文本.

3. 对于编号为 \10 或更大值的表达式, 如果存在与该编号对应的反向引用, 则将该表达式视为反向引用; 否则, 将这些表达式解释为八进制代码.

4. 如果正则表达式包含对未定义的组成员的反向引用, 则会发生分析错误, 并且正则表达式引擎将引发参数异常.

如果有多义性问题, 可以使用 \k<name> 表示法, 该表示法是明确的, 并且不会与八进制符号代码混淆. 同样, 如 \xdd 的十六进制代码是明确的, 并且不能与反向引用混淆.

下面的示例查找字符串单词中双写的字符:

字符串: trellis llama webbing dresser swagger

表达式: (\w)\1

匹配结果(标志 4):
[0]=> [0]ll
[1]=> [0]ll
[2]=> [0]bb
[3]=> [0]ss
[4]=> [0]gg

表达式分析:

模式 | 说明
(\w) | 匹配一个单词字符, 并将其分配给第一捕获组.
\1 | 匹配下一个字符, 即与第一捕获组相同的字符. 反向引用 .

命名组的后向引用: \k<name>

name 是正则表达式模式中定义的捕获组名字. 如果正则表达式模式中未定义 name, 则将发生分析错误, 并且正则表达式引擎将引发参数异常.

下面的示例查找字符串中双写的单词字符:

字符串: trellis llama webbing dresser swagger

表达式: (?<char>\w)\k<char>

匹配结果(标志 4):
[0]=> [0]ll
[1]=> [0]ll
[2]=> [0]bb
[3]=> [0]ss
[4]=> [0]gg

表达式分析:

模式 | 说明
(?<char>\w) | 匹配单词字符, 并将其分配给名为 char 的捕获组.
\k<char> | 匹配下一个字符, 即与 char 捕获组相同的字符. 命名组的反向引用 .

请注意 name 也可以是数字字符串的表示形式. 例如下面的示例使用正则表达式 (?<2>\w)\k<2> 与 (?<char>\w)\k<char> 效果完全相同.

反向引用匹配什么

反向引用总是指向最近的定义组(当从左到右匹配时, 最靠近左侧的定义). 当组建立多个捕获时, 反向引用会引用最近的捕获.

如果一个组尚未捕获任何子字符串, 则对该组的反向引用是未定义的并且永远不匹配. 如下面示例:

字符串: AA22ZZ, AABB

表达式: \b(\p{Lu}{2})(\d{2})?(\p{Lu}{2})\b

匹配结果(标志 4):
[0]=> [0]AA22ZZ
[0]=> [1]AA
[0]=> [2]22
[0]=> [3]ZZ
[1]=> [0]AABB
[1]=> [1]AA
[1]=> [2] ; 空匹配 , AABB 之间没有数字 .
[1]=> [3]BB

表达式分析:

模式 | 说明
\b | 从单词边界开始匹配.
(\p{Lu}{2}) | 匹配两个大写字母. 这是第一个捕获组.
(\d{2})? | 匹配两个十进制数的零个或一个匹配项. 这是第二个捕获组
(\p{Lu}{2}) | 匹配两个大写字母. 这是第三个捕获组
\b | 从单词边界结束匹配.

即使由第二个捕获组定义的两个十进制数字不存在( 例如子字符串 AABB 之间不存在数字 ) , 输入字符串也可以匹配此正则表达式 .

示例显示即使匹配成功, 仍会在两个成功的捕获组之间找到空捕获组.


正则表达式中的可选构造

可选构造可修改正则表达式以启用两者任一的条件匹配.

利用 | 的可选模式匹配

可以使用竖线 | 字符匹配一系列模式中的任意一种, 字符 | 分隔每种可选模式. 与正字符组相同, | 字符可用于匹配若干单个字符中的任何一个.

下面的示例使用正字符组和两者任一模式查找字符串中 gray 或 grey 单词的匹配项. 在这种情况时使用 | 字符会生成更为详细的正则表达式匹配结果.

字符串: The gray wolf blended in among the grey rocks.

表达式1: \bgr(a|e)y\b

表达式2: \bgr[ae]y\b

表达式1的匹配结果(标志 4):
[0]=> [0]gray
[0]=> [1]a
[1]=> [0]grey
[1]=> [1]e

表达式2的匹配结果(标志 4):
[0]=> [0]gray
[1]=> [0]grey

使用 | 字符的表达式 \bgr(a|e)y\b 分析:

模式 | 说明
\b | 在单词边界处开始.
gr | 匹配字符 gr
(a|e) | 匹配字符 a 或 e
y\b | 匹配单词边界中的 y . 并且结束一轮匹配过程 .

字符 | 也可用于多个字符或子表达式(包括文本字符和正则表达式语言元素的任意结合)执行两者任一匹配. (字符组则不提供此功能.)

下面示例使用 | 字符提取美国社会保障号 (SSN 格式为 ddd-dd-dddd 的 9 位数字), 或美国雇主标识号 (EIN 格式为 dd-ddddddd 的 9 位数字).

字符串: 01-9999999 020-333333 777-88-9999

表达式: \b(\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b

匹配结果(标志 3):
[0]01-9999999
[1]777-88-9999

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
(\d{2}-\d{7} | 匹配连字符连接的两个十进制数字和七个十进制数字;
|\d{3}-\d{2}-\d{4}) | 或者也可以 匹配三个十进制数字后接连字符, 后接两个十进制数字, 后接另一个连字符, 然后再接四个十进制数字.
\b | 在单词边界处结束.

条件匹配的表达式

此语言元素尝试根据是否可以匹配初始模式来匹配两种模式之一. 语法为: (?(?= 条件模式)yes|no)

条件模式是要匹配的初始模式, yes 是当条件模式匹配成功的要匹配模式, 而 no 是条件模式匹配失败时要匹配的可选模式.
正则表达式引擎将条件模式视为一个宽度为零的断言; 也就是说, 正则表达式引擎在计算条件模式之后, 不再处理输入流的后续数据.

语法构造中 (?=条件模式) 是一个零宽断言. (有关详细信息, 请参阅正则表达式中的分组子表达式. ) 正则表达式引擎将条件模式解释为定位点(有关详细信息, 请参阅正则表达式中的定位点), 或者是包含在 yes 中的子表达式. 否则, 无法匹配 yes 模式.

如果条件模式是命名捕获组或带编号的捕获组, 则可选构造将被解释为捕获测试; 正则表达式引擎不会尝试匹配捕获的子字符串, 而是测试该组是否存在.

下面的示例是利用 | 的两者任一模式匹配上节示例. 它使用条件匹配确定单词边界之后的前三个字符是否是后接一个连字符的两个数字. 如果是, 则将尝试匹配美国雇主标识号 (EIN). 如果不是, 则将尝试匹配美国社会保障号 (SSN).

字符串: 01-9999999 020-333333 777-88-9999

表达式: \b(?(?=\d{2}-)\d{2}-\d{7}|\d{3}-\d{2}-\d{4})\b

匹配结果(标志 3):
[0]01-9999999
[1]777-88-9999

表达式分析:

模式 | 说明
\b | 在单词边界处开始
(?(?=\d{2}-) | 条件定义. 确定接下来的三个字符是否由两个数字后接一个连字符组成.
\d{2}-\d{7} | 如果前面的条件模式匹配, 则匹配后接一个连字符和七个数字的两个数字
|\d{3}-\d{2}-\d{4}) | 如果前面的模式不匹配, 则匹配三个十进制数字, 后接一个连字符, 再接两个十进制数字, 再接另一个连字符, 再接四个十进制数字.
\b | 在单词边界处结束

基于有效捕获组的条件匹配

此语言元素尝试根据是否已经匹配指定的捕获组来匹配两种模式之一. 语法为: (?( name )yes|no) 或 (?(number )yes|no)

其中, name 是捕获组的名称, number 是捕获组的编号; yes 是当 name 或 number 具有匹配项时要匹配的表达式; 否则匹配 no 的可选表达式

如果 name 与正则表达式模式中所用捕获组的名称不对应, 则意味着条件模式的计算结果为 false. 如果 number 与正则表达式模式中所用编号的捕获组不对应, 则正则表达式引擎将引发参数异常.

下面的示例是上示例的变体. 它使用一个名为 n2 的捕获组, 其中包含两个数字, 后接一个连字符. 可选构造测试此捕获组是否在输入字符串中找到匹配项. 如果有匹配项, 则可选构造会尝试匹配九位数的美国雇主标识号 (EIN). 如果没有匹配项, 则将尝试匹配九位数的美国社会保障号 (SSN).

字符串: 01-9999999 020-333333 777-88-9999

表达式: \b(?<n2>\d{2}-)*(?(n2)\d{7}|\d{3}-\d{2}-\d{4})\b

匹配结果(标志 4):
[0]=> [0]01-9999999
[1]=> [0]777-88-9999

表达式分析:

模式 | 说明
\b | 在单词边界处开始.
(?<n2>\d{2}-)* | 匹配两个数字后接一个连字符的零或一个匹配项. 命名此捕获组 n2
(?(n2) | 测试输入字符串中是否有 n2 的匹配项
\d{7} | 如果找到 n2 的匹配项, 则匹配 7 个十进制数字
|\d{3}-\d{2}-\d{4}) | 如果未找到 n2 的匹配项, 则匹配 3 个十进制数字, 后接一个连字符, 再接 2 个十进制数字, 再接另一个连字符, 再接 4 个十进制数字.
\b | 在单词边界处结束.

下面示例中是上示例的变体, 使用编号组而非命名组:

字符串: 01-9999999 020-333333 777-88-9999

表达式: \b(\d{2}-)*(?(1)\d{7}|\d{3}-\d{2}-\d{4})\b

匹配结果(标志 4):
[0]=> [0]01-9999999
[1]=> [0]777-88-9999


捕获组应用限定符

由正则表达式捕获组匹配的子字符串如下所示:

1. 构造中的第一个组对象( 索引 0 )表示整个匹配.

2. 下一分组对象表示未命名编号的捕获组. 它们以在正则表达式中从左至右出现的顺序定义. 这些组的索引值范围从 1 到组中未命名捕获组的数目.

3. 命名捕获组以它们在正则表达式中从左至右的顺序出现定义 . 这些组的索引值范围从 1 到集合中命名捕获组的数目. 特定组索引等效于其编号的反向引用.

下面的示例描述分组和捕获对象之间的关系:

字符串 : This is a short sentence.

表达式 : (\b(\w+)\W+)+

匹配结果(标志 2):
[0]This is a short sentence.
[1]sentence.
[2]sentence

表达式分析:

模式 | 子模式 | 说明
\b |  | 在单词边界处开始匹配.
(\w+)\W+)+ |  | 一次或多次匹配跟在一个或多个非单词字符后面的一个或多个单词字符. 这是第一个捕获组.
 | (\w+) | 匹配一个或多个单词字符. 这些字符一起构成一个单词. 这是第二个捕获组
 | \W+ | 匹配一个或多个非单词字符.

第一个捕获组 ( 数组索引[1] ) 匹配连同标点符号及其该单词后的空白区域的单词; 第二个捕获组 ( 数组索引[2] ) 匹配不包含标点符号及其后空白区域的单词.

通过对捕获组应用限定符(有关详细信息, 请参阅正则表达式的限定符)可以按两种方式修改每个捕获组之间的关系有两种方式:

1. 如果对捕获组应用 * 或 *? 限定符(将指定零个或多个匹配项), 则捕获组在输入字符串中可能没有匹配项, 捕获组匹配失败, 返回长度为 0 的空值, 但能确保整个表达式匹配成功.

下面示例进行这方面的演示. 在正则表达式模式 aaa(bbb)*ccc 中:
输入字符串没有字符 b 序列, 捕获组 (bbb)* 因限定符 * 可以匹配 0 次(即允许不出现), 使得表达式可以匹配输入字符串 aaaccc , 而该捕获组没有匹配项. 但如果没有限定符 * , 则测试提示表达式没有匹配项.

字符串: aaaccc

表达式: aaa(bbb)*ccc

匹配结果(标志 1, 或 2, 或 3): [0]aaaccc

2. 限定符可以匹配由捕获组定义模式的多个匹配项. 在此情况下, 值对象的长度和组属性仅包含有关最后捕获的子字符串的信息.

例如下面的正则表达式匹配以句点结束的单个句子. 此表达式使用两个分组构造:
第一个分组构造 ((\w+)\s?) 捕获各个单词以及空白字符; 第二个分组构造 (\w+) 捕获各个单词.
如示例的输出所示, 虽然正则表达式成功捕获 2 个完整句子, 但由于限定符 + 的作用, 使得 2 个分组仅捕获了句子的最后一个单词.

字符串: This is a sentence. This is another sentence.

表达式: \b((\w+)\s?)+\.

匹配结果(标志 4):
[0]=> [0]This is a sentence.
[0]=> [1]sentence
[0]=> [2]sentence
[1]=> [0]This is another sentence.
[1]=> [1]sentence
[1]=> [2]sentence

表达式分析:

模式 | 子模式 | 说明
\b |  | 在单词边界处开始匹配
((\w+)\s?)+ |  | 匹配项目分述如下. 这是使用限定符的第一捕获组
 | (\w+) | 匹配 1 或多个单词字符. 这是第二捕获组
 | \s? | 匹配 0 个或 1 个空白符
 | + | 限定符 . 1 次或多次匹配上 2 项的集合

捕获集合

组对象仅包含有关最后一个捕获的信息. 但仍可从捕获收集属性返回的捕获组对象中获取由捕获组生成的整个捕获集合. 集合中的每个成员均为一个由该捕获组生成的捕获对象, 这些对象按被捕获的顺序排列(也就是遵循在输入字符串中按从左至右匹配捕获的字符串顺序). 可以通过返回的数组索引来检索集合中的各个捕获对象.

如果不对捕获组应用限定符, 则捕获收集对象将包含一个捕获对象, 但该对象的作用不大, 因为它提供的是有关与其组对象相同的匹配项信息. 如果对一个捕获组应用限定符, 则捕获收集对象将包含该捕获组所生成的所有捕获, 并且集合的最后一个成员将表示与组对象相同的捕获.

例如使用正则表达式 ((a(b))c)+ (限定符 + 指定匹配一个或多个匹配项)捕获字符串 bcabcabc 中的匹配项, 则每个捕获收集对象的组对象都将包含三个成员.

匹配结果(标志 2):
[0]abcabcabc
[1]abc ; 成员 1
[2]ab ; 成员 2
[3]b ; 成员 3

下面示例使用正则表达式 (Abc)+ 在字符串 XYZAbcAbcAbcXYZAbcAb 中查找字符串 Abc 的一个或多个连续匹配项. 该示例演示了使用组捕获属性来返回多组捕获的子字符串.

匹配结果(标志 4):
[0]=> [0]AbcAbcAbc ; 开始于位置 3
[0]=> [1]Abc ; 开始与位置 6
[1]=> [0]Abc ; 开始与位置 6
[1]=> [1]Abc ; 开始与位置 9

单个捕获

捕获来自单个子表达式捕获的结果. 捕获值为匹配的文本.

下面示例分析选定城市温度的输入字符串. 逗号 , 用于将城市名称与其温度值分隔开, 而分号 ; 用于将每个城市的数据分隔开.

用于分析字符串的正则表达式模式 ((\w+(\s\w+)*),(\d+);) 中, 城市名称将分配给第二个捕获组( 对应 => [2] ) , 而温度值将分配到第四个捕获组( 对应 => [4] ) .

字符串: Miami,78;Chicago,62;New York,67;San Francisco,59;Seattle,58;

匹配结果(标志 4):

[0]=> [0]Miami,78;
[0]=> [1]Miami,78;
[0]=> [2]Miami
[0]=> [3]
[0]=> [4]78 		[1]=> [0]Chicago,62;
[1]=> [1]Chicago,62;
[1]=> [2]Chicago
[1]=> [3]
[1]=> [4]62 		[2]=> [0]New York,67;
[2]=> [1]New York,67;
[2]=> [2]New York
[2]=> [3] York
[2]=> [4]67 		[3]=> [0]San Francisco,59;
[3]=> [1]San Francisco,59;
[3]=> [2]San Francisco
[3]=> [3] Francisco
[3]=> [4]59 		[4]=> [0]Seattle,58;
[4]=> [1]Seattle,58;
[4]=> [2]Seattle
[4]=> [3]
[4]=> [4]58

表达式分析:

模式 | 子模式1 | 子模式2 | 说明
((\w+(\s\w+)*),(\d+);) |  |  | 匹配以下所有子模式的捕获集合. 是第一个捕获组.
 | (\w+(\s\w+)*) |  | 0 次 或多次匹配以下子模式2 的捕获集合. 这是第二个捕获组.
 |  | \w+ | 匹配一个或多个单词字符.
 |  | (\s\w+)* | 匹配一个空白字符后跟 0 个或多个单词字符. 此模式匹配多单词的城市名称. 这是第三个捕获组. 对应 => [3] , 捕获多单词城市名称的最后单词 , 否则为空值 .
 | , |  | 匹配逗号.
 | (\d+) |  | 匹配一个或多个数字. 这是第四个捕获组. 温度值 , 对应 => [4] .
 | ; |  | 匹配分号.


位置定义

对于字符串 "a5" , 由两个字符 "a" 、 "5" 以及三个位置组成的, 这一点对于正则表达式的匹配原理理解很重要.

左右方向定义

正则表达式引擎尝试匹配输入字符串时, 按从左到右的顺序执行搜索. 因此字符串的左侧为顺序(正)方向 , 而右侧则为逆序(负)方向 .

断言

断言的作用相当于对所在位置加了一个附加条件, 只有满足这个条件, 断言模式才能匹配成功. 断言的难点在于找到这个"位置".

断言只进行断言模式的匹配, 不占有字符, 即匹配到的内容不保存到最终的匹配结果中, 是零宽度的. 断言匹配的最终结果就是一个位置.

断言按照方向划分有预测先行(顺序)断言和回顾后发(逆序)断言两种, 按照是否匹配有肯定(正)和否定(负)两种, 组合起来就有四种断言形式(见下表).

预测先行断言相当于在当前位置右侧附加一个条件, 而回顾后发断言相当于在当前位置左侧附加一个条件.

表达式 | 说明
(?<=断言模式) | 正回顾后发断言 -- 所在位置左侧能够匹配断言模式.
(?<!断言模式) | 负回顾后发断言 -- 所在位置左侧不能匹配断言模式.
(?=断言模式) | 正预测先行断言 -- 所在位置右侧能够匹配断言模式.
(?!断言模式) | 负预测先行断言 -- 所在位置右侧不能匹配断言模式.

举例说明:

正回顾后发断言示例:
(?<=Windows )\d+ 在匹配 Windows 2003 时, 匹配结果为 “2003”. \d+ 表示匹配一个以上的数字, 而 (?<=Windows ) 相当于一个附加条件, 表示所在位置左侧必须为 "Windows ", 它所匹配的内容并不计入匹配结果. 同样的正则在匹配 Office 2003 时, 匹配失败, 因为这里任意一串数字子串的左侧都不是"Windows ".

正回顾后发断言示例:
(?<=\d{4})\w+ 在匹配 "1234abcdef" 时, 将匹配除前 4 个数字之外的其它剩余字符, 捕获匹配项的前面必须有 4 个十进制数字 .

正预测先行断言示例:
Windows (?=NT|XP) 在匹配 "Windows 98, Windows NT, Windows 2000" 时, 将只匹配 "Windows NT" 中的 "Windows ", 其它 "Windows " 字符后面都不符合"后跟 NT 或 XP" 的条件 因此都不被匹配.

负预测先行断言示例:
(?!1)\d+ 在匹配 "123" 时, 匹配结果为 "23". \d+ 匹配一个以上的数字, 但是附加条件 (?!1) 要求所在位置右侧不能是 1 , 所以匹配成功是从位置 1 开始, 匹配 "23" .

混合使用示例:
(?<=\d{4})\w+(?=\d{4}) 在匹配 "1234abcd3456" 时, 将匹配除了前 4 个数字和后 4 个数字之外的字母字符 abcd


正预测先行断言: (?=断言模式)

子表达式为任何正则表达式模式. 若要成功匹配, 则输入字符串必须存在能匹配断言模式的子字符串, 尽管匹配的子字符串不会包含到匹配结果中.

零宽正预测先行断言不会回溯. 匹配时向右搜索断言模式.

通常零宽正预测先行断言是在正则表达式模式的末尾找到的. 它定义一个子字符串, 该子字符串必须出现在匹配字符串的末尾但又不能包含在匹配结果中.

零宽正预测先行断言能确保特定捕获组从与断言模式匹配的文本开始开始捕获.

对于 (?=断言模式) 来说, 当断言模式匹配成功时, (?=断言模式) 匹配成功, 但这个匹配不会包含在最终匹配结果中!

通常正预测先行断言定义在正则表达式模式的末尾. 它定义一个断言子字符串, 该子字符串必须出现在匹配字符串的后面但又不能包含在匹配结果中. 这有助于防止过度回溯.

正预测先行断言功能允许回溯引擎在匹配断言模式后返回到文本中相同的作用点. 这对于通过验证起始于相同位置的多个模式搜索整个文本是很有用的. 它还允许引擎验证匹配的结尾是否存在某个子字符串, 而无需在匹配的文本中包含该子字符串. 下面的示例使用正预测先行从句子中提取未后无标点符号的单词.

字符串: If so, what comes next?

表达式: (?i)\b[A-Z]+\b(?=\P{P})

匹配结果: [0]=If [1]what [2]comes

表达式分析:

模式 |
(?i) | 从此处开始, 匹配不区分大小写.
\b | 在单词边界处开始匹配.
[A-Z]+ | 不区分大小写与任意字母字符匹配一次或多次.
\b | 在单词边界处结束匹配.
(?=\P{P}) | 查看前一个字符来确定下一个字符是否为标点符号. 如果不是, 则表明匹配成功.

下面示例匹配输入字符串中谓词 is 前面的单词:

字符串:
The dog is a Malamute.
The island has beautiful birds.
The pitch missed home plate.
Sunday is a weekend day.

表达式: \b\w+(?=\sis\b)

匹配结果(标志 3):
[0]dog 单词 is 前面的单词
[1]Sunday 单词 is 前面的单词

' The island has beautiful birds. ' 与 ' The pitch missed home plate. ' 中的 is 后面没有空格, 都不是单词, 因此都不匹配这个正则表达式 .

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
\w+ | 匹配一个或多个单词字符 .
(?=\sis\b) | 正预测先行断言. 确定单词结束的后面是否有空白字符并紧跟单词字符串 is . 如果是, 则该单词匹配成功. 断言模式指定这样一个条件 : 空白符 \s 后跟 2 个字母 is 再后跟单词边界 \b . \w+ 匹配到一个单词后 , 立即从当前单词的结束位置顺序向前检查该单词其后是否有一个匹配断言模式的字符串 is , 如果有 , 则匹配成功 , 并将这个单词保存到最终匹配结果中 , 但不保存匹配断言模式的字符串 is , 否则匹配失败 .

匹配过程分析

字符串 : a12

表达式 : ^(?=[a-z])[a-z0-9]+$

匹配结果(标志 1 或 2 或 3) : [0]a12

元字符 ^ 和 $ 匹配的只是位置, 正预测先行断言 (?=[a-z]) 只进行匹配, 并不占有字符, 也不将匹配的内容保存到最终的匹配结果, 所以都是零宽度的.

1. 首先由元字符 ^ 取得控制权, 从位置 0 开始匹配. ^ 匹配的就是开始位置 0 , 匹配成功后控制权交给正预测先行断言 (?=[a-z]).

2. 正预测先行断言 (?=[a-z]) 要求它所在位置左侧(后面)必须是一个字母才能匹配成功, 0 宽度的断言模式之间是不互斥的, 即同一个位置可以同时由多个 0 宽度断言模式匹配, 所以它也是从位置 0 尝试进行匹配, 位置 0 的右侧是字符 a , 符合要求, 匹配成功, 控制权交给 [a-z0-9]+.

3. 因为 (?=[a-z]) 只进行匹配, 并不将匹配到的内容保存到最后结果, 并且匹配成功的只是位置 0, 所以 [a-z0-9]+ 也是从位置 0 开始尝试匹配的, [a-z0-9]+ 首先尝试匹配 a , 匹配成功, 继续尝试匹配, 可以成功匹配接下来的 1 和 2 , 此时已经匹配到位置 3, 位置 3 的右侧已没有字符, 这时会把控制权交给 $.

元字符 $ 从位置 3 开始尝试匹配, 它匹配的是结束位置, 也就是位置 3 , 匹配成功.

此时正则表达式匹配完成, 报告匹配成功. 匹配结果为 a12 , 开始位置为 0, 结束位置为 3. 其中 ^ 匹配位置 0, (?=[a-z]) 匹配位置 0, [a-z0-9]+ 匹配字符串 a12 , $ 匹配位置 3.

注意 : 这里的正预测先行断言 (?=[a-z]) 定义在整体表达式的开头 , 而上面示例是将断言模式 (?=\sis\b) 定义在正则表达式的末尾 !


正回顾后发断言: (?<=断言模式)

断言模式为任何正则表达式模式. 若要成功匹配, 则断言模式匹配项不得在输入字符串当前位置左侧出现, 尽管断言模式的匹配结果不会包含在最终匹配结果中.

断言模式为 0 宽度断言, 不会回溯. 回顾后发断言匹配时向左搜索断言模式.

正回顾后发断言通常在正则表达式的开头使用. 断言模式只是一个匹配的前提条件, 它不是匹配结果的一部分.

下面的示例匹配 21 世纪年份的最后两个数字(也就是说, 数字 20 要在匹配字符串之前）.

字符串: 2010 1999 1861 2140 2009

表达式: (?<=\b20)\d{2}\b

匹配结果(标志 3) : [0]10 [1]09

表达式分析:

模式 | 说明
\d{2} | 匹配两个十进制数字. 如果断言模式成功匹配, 则继续匹配 2 个数字 .
(?<=\b20) | 正回顾后发断言. 如果两个十进制数字的左侧边界以 20 开头, 则匹配失败, 继续寻找匹配. 断言匹配条件 -- 匹配的字符串必须以 20 开头 .
\b | 在单词边界处结束匹配. 如果 \d{2} 成功匹配 , 则在 \d{2} 的结束边界处结束匹配 .

下面示例正则表达式 (*UCP)(?<=\d){1,2}\s\w+,?\s\d{4} 使用回顾后发断言测试月份名称前面的日期; 然后该正则表达式匹配月份和年份

字符串: "1 五月 1917", "六月 16, 2003"

表达式: (*UCP)(?<=\d){1,2}\s\w+,?\s\d{4}

匹配结果(标志 1, 或 2, 或 3): [0] 五月 1917
"六月 16, 2003" 因其开头不是十进制数字 , 所有不能匹配 .

表达式分析:

模式 | 说明
(*UCP) | 启动 Unicode 类别属性(UCP)支持, 匹配中文字符串.
(?<=\d) | 正回顾后发断言. 匹配项的开头必须为十进制数字.
{1,2} | 匹配前项捕获值 1 到 2 次.
\s | 匹配空白字符.
w+,? | 匹配一个或多个单词字符.
\s | 匹配空白字符.
\d{4} | 匹配 4 个十进制数字.

字符串 : Windows 2003

表达式 : (?<=Windows\s)\d+

匹配结果(标志 1, 或 2, 或 3) : [0]2003
说明 : \d+ 表示匹配一个以上的数字, 而 (?<=Windows\s) 相当于一个附加条件, 表示所在位置左侧必须为断言模式 Windows\s , 这个匹配的内容不计入匹配结果.
这个正则表达式在匹配字符串 Office 2003 时匹配失败, 因为这里任意一串数字子串的左侧都没有断言模式 Windows\s .

正回顾后发断言匹配过程

字符串 : <div>a test</div>

表达式 : (?<=<div>)[^<]+(?=</div>)

这个正则的意义就是匹配<div>和</div>标签之间的内容, 而不包括<div>和</div>标签本身.

匹配过程 :

1. 首先由正回顾后发断言 (?<=<div>) 取得控制权, 从位置 0 开始匹配, 由于位置 0 是起始位置, 左侧没有任何内容, 所以 <div> 必然匹配失败, 从而正回顾后发断言 (?<=<div>) 匹配失败, 导致整个表达式在位置 0 处匹配失败. 第一轮迭代匹配失败, 正则引擎向前传动, 由位置 1 处开始尝试第二次迭代匹配.

2. 直到传动到位置 5, (?<=<div>) 取得控制权, 向左查找 5 个位置, 由位置 0 开始匹配, 由 <div> 匹配 <div> 成功, 从而 (?<=<div>) 匹配成功, 匹配的结果为位置 5, 控制权交给 [^<]+ 从位置 5 开始尝试匹配, 尝试匹配文本 a test .

3. 控制权交给正预测先行断言 (?=</div>) , 匹配 </div> 成功, 从而 (?=</div>) 匹配成功, 匹配结果为位置 11.

此时正则表达式匹配成功完成. 匹配结果为 a test , 开始位置为 5, 结束位置为 11. 其中 (?<=<div>) 匹配位置 5, [^<]+ 匹配 a test , (?=</div>) 匹配位置 11.

负回顾后发断言 (?<!断言表达式) 的匹配过程与上述过程类似, 区别只是当断言模式匹配失败时, 负回顾后发断言 (?<!断言表达式) 才匹配成功.

正回顾后发断言的特殊处在于, 它相当于在当前位置左侧附加一个条件, 所以它不是在当前位置开始尝试匹配的, 而是从当前位置左侧某一位置开始, 匹配到当前位置为止, 报告匹配成功或失败.


负回顾后发断言 (?<!断言模式)

对于负回顾后发断言 (?<!断言模式) 来说, 当断言模式匹配成功时, (?<!断言模式) 匹配失败; 当断言模式匹配失败时, (?<!断言模式) 匹配成功. 断言模式为 0 宽度.

断言模式为任何有效的正则表达式模式. 若要成功匹配, 则断言模式的匹配项不得在输入字符串当前位置的左侧出现, 并且任何不匹配断言模式的子字符串不包含在匹配结果中.

负回顾后发断言通常定义在正则表达式的开头, 它们定义的模式预先排除后面字符串中的匹配项. 它们还用于在捕获组中的最后一个或多个字符不得为与该捕获组正则表达式的断言模式相匹配的其中一个或多个字符时限制回溯. 回顾后发断言匹配时向左搜索断言模式.

下面示例匹配除周末之外的一周的任何一天(也就是不包含星期六和星期日).

字符串:
Monday February 1, 2010,
Wednesday February 3, 2010
Saturday February 6, 2010
Sunday February 7, 2010
Monday February 8, 2010

表达式: (?<!Saturday |Sunday )\b\w+ \d{1,2}, \d{4}\b

匹配结果(标志 3):
[0]February 1, 2010
[1]February 3, 2010
[2]February 8, 2010

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
\w+ | 匹配一个或多个后跟空格字符的单词字符, 注意 + 后有一个空格! 由此可见空格字符可以不用 \s 表示.
\d{1,2}, | 匹配一个或两个十进制数字, 并且后跟一个逗号.
\d{4}\b | 匹配单词结束边界前的四个十进制数字, 并结束一轮匹配.
(?<!Saturday |Sunday ) | 如果字符串以 “Saturday ” 或者 “Sunday ”(后跟一个空格)开头, 则 (?<!Saturday |Sunday ) 匹配成功. \b\w+ \d{1,2}, \d{4}\b 存在匹配项后 , 负回顾 ( 向后 ) 检查匹配项前面的断言模式是否匹配 , 如果断言模式匹配成功, 则 \b\w+ \d{1,2}, \d{4}\b 的匹配项不记录到表达式的最终匹配结果中 . 否则匹配项保存到最终匹配结果中 .


负预测先行断言: (?!断言模式)

断言模式为有效正则表达式模式. 若要成功匹配, 则输入字符串必须不匹配断言模式的匹配项, 尽管断言模式的匹配项不会包含到最终匹配结果中.

预测先行断言匹配时向右搜索断言模式.

负预测先行断言通常用在正则表达式的开头或结尾:
定义在正则表达式的开头, 表示不能在匹配项的开头处出现断言模式指定的字符串.
定义在正则表达式的末尾, 表示不能在匹配项的末尾处出现断言模式的指定字符串.

负预测先行功能只在断言模式匹配失败的情况下表达式才能成功匹配. 这对于删改一个搜索特别有用, 因为提供应被排除的断言模式通常比提供必须被包括在内的表达式要简单一些.

例如, 编写搜索不以 non 起始的单词的表达式就很困难. 下面的示例使用负预测先行来排除它们.

字符串: Nonsense is not always non-functional.

表达式: \b(?!non)\w+\b

匹配结果(标志 3):
[0]Nonsense Non 不匹配断言模式的 non
[1]is
[2]not
[3]always
[4]functional

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
(?!non) | 查看前一个字符以确保当前字符串不以 non 开始. 如果当前字符串以 non 开始, 则匹配失败.
\w+ | 匹配一个或多个单词字符.
\b | 在单词边界处结束匹配.

下面示例在正则表达式开头使用负预测先行断言定义, 以匹配不以字符串 un 开头的单词.

字符串: unite one unethical ethics use untie ultimate

表达式: \b(?!un)\w+\b

匹配结果(标志 3):
[0]one
[1]ethics
[2]use
[3]ultimate

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配.
(?!un) | 负预测先行断言. 确定 \b 后接下来的两个字符是否为 un , 如果不是则可以匹配. 如果 (?!un) 匹配成功 , 则匹配结果及其后的 1 或多个单词字符排除在最终匹配结果之外 ; 如果 (?!un) 匹配失败 , 则捕获的 1 或多个单词字符串包含到最终结果中 .
\w+ | 匹配一个或多个单词字符.
\b | 在单词边界处结束匹配.

下面的示例在正则表达式的末尾使用负预测先行断言定义, 以匹配不以标点字符结束的单词:

字符串: Disconnected, disjointed thoughts in a sentence fragment.

表达式: \b\w+\b(?!\p{P})

匹配结果(标志 3):
[0]disjointed
[1]thoughts
[2]in
[3]a
[4]sentence

表达式分析:

模式 | 说明
\b | 在单词边界处开始匹配
\w+ | 匹配一个或多个单词字符.
\b | 在单词边界处结束匹配.
(?!\p{P}) | 负预测先行断言. 如果下个字符不是一个标点符号(如句点或逗号)则匹配成功. 检查 \b\w+\b 匹配项的左侧 ( 前面 , 负预测 , )是否有 \p{P} 匹配的标点符号 : 如果 (?!\p{P}) 匹配成功 , 则最终匹配结果排除 \b\w+\b 的匹配项 ; 如果 (?!\p{P}) 匹配失败 , 则最终匹配结果包含 \b\w+\b 的匹配项 .

负预测先行断言匹配过程:

字符串: aa<p>one</p>bb<div>two</div>cc

表达式: <(?!/?p\b)[^>]+>

匹配结果(标志 3) : [0]<div> [1]</div>

这个正则的意义就是匹配除 <p> 或 </p> 之外的其余标签.

首先由字符 < 取得控制权, 从位置 0 开始匹配, 由于 < 匹配 " a " 失败, 在位置 0 处整个表达式匹配失败, 第一次迭代匹配失败, 正则引擎向前传动, 由位置 1 处开始尝试第二次迭代匹配. 重复前面过程, 直到位置 2, < 匹配成功, 控制权交给 (?!/?p\b) ;

断言模式 (?!/?p\b) 取得控制权后, 进行断言模式内部的匹配. 首先由 /?( 0 个或 1 个反斜杠 ) 取得控制权, 尝试匹配字符 p 失败, 进行不匹配回溯, 控制权交给 p 尝试匹配 p , 匹配成功, 控制权交给 \b 尝试匹配位置 4, 匹配成功. 此时断言模式 /?p\b 匹配成功, 那么负预测先行断言 (?!/?p\b) 就匹配失败. 在位置 2 处整个表达式匹配失败, 新一轮迭代匹配失败, 正则引擎向前传动, 由位置 3 处开始尝试下一轮迭代匹配.

在位置 8 处也会遇到一轮 /?p\b 匹配 /p 成功, 而导致负预测先行断言 (?!/?p\b) 匹配失败, 从而导致整个表达式匹配失败.

重复以上过程, 直到位置 14, < 匹配成功, 控制权交给 (?!/?p\b) ; /? 尝试匹配反斜杠 / 失败, 进行不匹配回溯, 控制权交给 p 尝试匹配 , 匹配失败, 已经没有备选状态可供回溯, 匹配失败. 此时断言模式匹配完成, /?p\b 匹配失败, 那么负预测先行断言 (?!/?p\b) 匹配成功. 匹配的结果是位置 15, 然后控制权交给 [^>]+ ; 由 [^>]+ 从位置 15 进行尝试匹配, 可以成功匹配到 div , 控制权交给 > 来匹配 > .

此时正则表达式匹配完成, 报告匹配成功. 匹配结果为 <div> , 开始位置为 14, 结束位置为 19. 其中 < 匹配字符 < , (?!/?p\b) 匹配位置 15, [^>]+ 匹配字符串 div , > 匹配字符 > .


正则表达式中的回溯

正则表达式前进到子表达式的下一个语言元素并且匹配不成功时, 正则表达式引擎可放弃其成功匹配的一部分, 并返回以前保存的正则表达式与输入字符串匹配有关的状态. 返回到以前保存状态以查找匹配的这一过程称为回溯.

通常正则表达式引擎使用线性进度在输入字符串中移动. 当正则表达式模式包含可选限定符或可选构造时, 会发生回溯, 并且正则表达式引擎会返回以前保存的状态, 并继续搜索匹配项, 以便成功完成整个模式的匹配.

回溯是正则表达式强大功能的中心; 它使得表达式强大, 灵活, 可以匹配非常复杂的模式. 同时, 这种强大功能需要付出一定代价.

通常, 回溯是影响正则表达式引擎性能的单个最重要的因素. 幸运的是正则表达式编写者可以控制正则表达式引擎的行为及其回溯的使用方式. 本主题说明回溯的工作方式. 回溯的控制见这里.

不使用回溯的线性比较

如果正则表达式模式没有可选限定符或可选构造, 正则表达式引擎将以线性时间执行. 正则表达式引擎将模式中的第一个语言元素与输入字符串中的文本匹配后, 它尝试将模式中的下一个语言元素与输入字符串中的下一个字符或字符组合匹配. 此操作将继续, 直至匹配成功或失败. 在任何一种情况下, 在同一时间, 正则表达式引擎都比输入字符串中提前一个字符.

下面示例进行这方面的演示. 正则表达式 e{2}\w\b 查找字母 "e" 后跟任意单词字符再后跟单词边界的两个匹配项.

字符串: needing a reed

表达式: e{2}\w\b

匹配结果(标志 1, 或 2, 或 3): [0]eed

表达式分析:

模式 | 说明
e{2} | 匹配 2 个字符 e .
\w | 字符组 [0-9a-zA-Z_] 的简记形式. 匹配任何一个数字, 或一个任意字母, 或一个下划线 "_"
\b | 在单词边界处结束匹配.

尽管此正则表达式包括限定符 {2}, 但它仍以线性方式进行计算. 由于 {2} 不是可选的限定符, 它指定确切数字, 而不是前一个子表达式必须匹配的可变次数. 因此该正则表达式引擎不回溯.

使用可选限定符或可选构造的回溯

当正则表达式模式包含可选限定符或可选构造时, 输入字符串的计算将不再为线性. 模式匹配由正则表达式中的语言元素驱动, 而不是由输入字符串中要匹配的字符驱动. 因此, 正则表达式引擎将尝试完全匹配可选或可替换的子表达式.

例如正则表达式模式 .*(es), 它匹配字符 es 以及它前面的所有字符. 如果输入字符串为 Essential services are provided by regular expressions. 模式将匹配 expressions 之前且包括 es 在内的整个字符串.

字符串: Essential services are provided by regular expressions.

表达式: .*(es)

匹配结果(标志 2):
[0]Essential services are provided by regular expres ; 从位置 0 开始的匹配结果
[1]es ; 从位置 47 开始的匹配结果.

正则表达式引擎按如下所示使用回溯:

1. 将 .* (它对应于出现零次, 一次或多次的任意字符)与整个输入字符串匹配.

2. 尝试在正则表达式模式中匹配 e . 但输入字符串没有剩余的可用字符来匹配.

3. 回溯到上一次成功的匹配 "Essential services are provided by regular expressions" , 并尝试将 e 与句尾的句号匹配. 匹配失败.

4. 继续回溯到上一个成功匹配, 一次一个字符, 直至临时匹配的子字符串为 "Essential services are provided by regular expr" . 然后, 它将模式中的 e 与 expressions 中的第二个 e 进行比较, 并找到匹配.

5. 将模式中的 s 与匹配的 e 字符之后的 s (“expressions"中的第一个 s )进行比较. 匹配成功.

当您使用回溯将正则表达式模式与输入字符串(长度为 55 个字符)匹配时, 需要执行 67 次比较操作. 有趣的是, 如果正则表达式模式包括惰性限定符 .*?(es), 则匹配正则表达式将需要进行更多次比较. 在此情况下, 不必从字符串末尾回溯到 expressions 中的 r , 正则表达式引擎必须一直回溯到字符串开头来匹配 Es , 将需要进行 113 次比较. 通常, 如果正则表达式模式包括单个可选构造或单个可选限定符, 则匹配模式所需要的比较操作数大于输入字符串中字符数的两倍.

使用嵌套可选限定符的回溯

如果模式中包括大量可选构造, 嵌套的可选构造(或最常见的是嵌套的可选限定符), 则匹配正则表达式模式所需要的比较操作数会成指数增加.

例如正则表达式模式 (a+)+ 用于匹配包含一个或多个 a 字符的完整字符串. 该示例提供了两个长度相同的输入字符串, 但只有第一个字符串与模式匹配.

字符串: aaaaaa, aaaaa!

表达式: (a+)+

匹配结果(标志 1): [0]aaaaaa

正如示例输出所示, 正则表达式引擎查找输入字符串与模式不匹配所需的时间大约为标识匹配字符串所需时间的两倍. 这是因为, 不成功的匹配始终表示最糟糕的情况. 正则表达式引擎必须使正则表达式遵循通过数据的所有可能路径, 然后才能得出匹配不成功的结论, 嵌套的括号会创建数据的许多其他路径. 正则表达式引擎通过执行以下操作来确定第二个字符串与模式不匹配：

1. 检查字符串开头, 然后将字符串中的前五个字符与模式 a+ 匹配. 然后确定字符串中没有其他成组的 a 字符. 最后, 它测试是否位于字符串结尾. 由于还有一个附加字符保留在字符串中, 所以匹配失败. 这一失败的匹配需要进行 9 次比较. 正则表达式引擎也从其 a(我们将其称为匹配 1), aa(匹配 2), aaa(匹配 3)和 aaaa(匹配 4)的匹配中保存状态信息.

2. 返回到以前保存的匹配 4. 它确定没有一个附加的 a 字符可分配给其他捕获组. 最后, 它测试是否位于字符串结尾. 由于还有一个附加字符保留在字符串中, 所以匹配失败. 该失败的匹配需要进行 4 次比较. 到目前为止, 总共执行了 13 次比较.

3. 返回到以前保存的匹配 3. 它确定有两个附加的 a 字符可分配给其他捕获组. 但是, 字符串末尾测试失败. 然后, 它返回 匹配 3 , 并尝试在两个附加的捕获组中匹配两个附加的 a 字符. 字符串末尾测试仍失败. 这些失败的匹配需要进行 12 次比较. 到目前为止, 总共执行了 25 次比较.

输入字符串与正则表达式的比较将以此方式继续, 直到正则表达式引擎已尝试所有可能的匹配组合然后得出无匹配的结论. 因为存在嵌套的限定符, 所以此比较为 2 的 n 次方或指数操作, 其中 n 是输入字符串中的字符数. 这意味着在最糟糕的情况下, 包含 30 个字符的输入字符串大约需要进行 1,073,741,824 次比较, 包含 40 个字符的输入字符串大约需要进行 1,099,511,627,776 次比较. 如果使用上述长度甚至更长的字符串, 则正则表达式方法在处理与正则表达式模式不匹配的输入时, 会需要超长的时间来完成.


回溯的控制

通过回溯可以创建强大, 灵活的正则表达式. 回溯在提供这些优点的同时, 可能也会使性能差得无法接受. 因此要防止过度回溯.

误用回溯或依赖过多回溯通常会显著降低正则表达式的性能. 在最糟糕的情况下, 输入字符串中每增加一个字符, 执行时间会加倍. 实际上, 如果过多使用回溯, 则在输入与正则表达式模式近似匹配时很容易创建无限循环的编程等效形式; 正则表达式引擎可能需要几小时甚至几天来处理相对短的输入字符串.

尽管回溯不是匹配所必需的, 但应用程序会因使用回溯而对性能产生负面影响. 例如正则表达式 \b\p{Lu}\w*\b 将匹配以大写字符开头的所有单词, 如下表所示:

模式 | 说明
\b | 在单词边界处开始匹配.
p{Lu} | 匹配大写字符.
\w* | 匹配零个或多个单词字符.
\b | 在单词边界处结束匹配.

由于单词边界与单词字符不同, 也不是单词字符的子集, 因此正则表达式引擎在匹配单词字符时将跨越单词边界. 这意味着对于正则表达式而言, 回溯对任何匹配的总体成功不会有任何贡献 -- 由于正则表达式引擎被强制保存每个单词字符的成功匹配的状态, 因此它只会降低性能.

回溯控制支持以下三个正则表达式语言元素, 这些元素限制或禁止回溯, 并支持对性能没有负面影响或负面影响很小的复杂正则表达式:
非回溯子表达式, 回顾断言, 预测先行断言.

非回溯子表达式

如果你确定不需要回溯, 则可使用 (?>子表达式) 语言元素禁止在子表达式中使用回溯. 它可用于预防与匹配失败关联的性能问题.

上面描述的表达式 \b\p{Lu}\w*\b 依赖于回溯, 将其修改为 \b\p{Lu}(?>\w*)\b 则会禁用回溯.
用这 2 个表达式分别匹配字符串 This this word Sentence name Capital , 这两个正则表达式产生的结果相同.

下面的示例演示使用嵌套限定符时禁止回溯如何改进性能. 它测量正则表达式引擎确定输入字符串与两个正则表达式不匹配( 即两个表达式都没有匹配项 )所需要的时间.

第一个正则表达式使用回溯尝试匹配一个字符串, 在该字符串中, 一个或多个十六进制数出现一次或多次, 然后依次为冒号, 一个或多个十六进制数, 两个冒号.

第二个正则表达式与第一个相同, 不同之处是它禁用了回溯. 测试可见禁用回溯对性能的改进非常显著.

字符串: b51:4:1DB:9EE1:5:27d60:f44:D4:cd:E:5:0A5:4a:D24:41Ad:

回溯子表达式 : (([0-9a-fA-F]{1,4}:)*([0-9a-fA-F]{1,4}))*(::)

非回溯子表达式 : ((?>[0-9a-fA-F]{1,4}:)*(?>[0-9a-fA-F]{1,4}))*(::)

分别使用这 2 个表达式测试, 回溯子表达式耗时高达 250 毫秒以上, 而非回溯子表达式耗时仅 0.1 毫秒左右.

回顾断言

包括两个语言元素 (?<=断言模式) 和 (?<!断言模式), 它们与输入字符串中的前面一个或多个字符匹配. 这两个语言元素都是零宽度断言; 它们通过断言模式而不是前移或回溯来确定当前字符之前紧挨着的一个或多个字符是否匹配.

(?<= 断言模式) 是正回顾断言; 当前位置之前的一个或多个字符必须与 断言模式 匹配.
(?<! 断言模式) 是负回顾断言; 当前位置之前的一个或多个字符不得与断言模式匹配.
当断言模式为前一个子表达式的子集时, 正回顾断言和负回顾断言都最为有用.

在许多情况下正则表达式模式与输入文本匹配时, 回溯很重要. 但过度回溯会严重降低性能, 并且会产生应用程序已停止响应的感觉. 特别需要指出的是, 当嵌套限定符并且与外部子表达式匹配的文本为与内部子表达式匹配的文本的子集时, 尤其会出现这种情况.

例如正则表达式模式 [0-9A-Z]([-.\w]*[0-9A-Z])*\$ 用于匹配至少包括一个字母数字字符的部件号. 任何附加字符可以包含字母数字字符, 连字符, 下划线或句号, 但最后一个字符必须为字母数字. 美元符号用于终止部件号. 在某些情况下, 由于限定符嵌套并且子表达式 [0-9A-Z] 是子表达式 [-.\w]* 的子集, 因此此正则表达式模式会表现出极差的性能.

此时可通过移除嵌套限定符并将外部子表达式替换为零宽度预测先行和回顾断言来优化正则表达式性能. 预测先行和回顾断言是定位点; 它们不在输入字符串中移动指针, 而是通过预测先行或回顾来检查是否满足指定条件. 例如可将部件号正则表达式重写为 [0-9A-Z][-.\w]*(?<=[0-9A-Z])\$. 此正则表达式模式的定义如下表所示:

表达式 | 说明
[0-9A-Z] | 匹配一个字母或数字字符. 部件号至少要包含一个此类字符.
[-.\w]* | 匹配零个或多个任意单词字符, 或连字符, 或句号.
\$ | 转义 $ 字符匹配美元符号.
(?<=[0-9A-Z]) | 正回顾断言. 查看美元符号结束的前面是否为一个字母或数字.

此表达式与字符串 A1C$, A4, A4$, A1603D$, A1603D# 匹配时, 将匹配红标部分, 其它 2 个不匹配.

下面示例使用 2 个等效正则表达式模式. 第一个模式由于过多使用回溯, 性能极差. 第二个模式通过将嵌套的限定符替换为正回顾断言来修改第一个正则表达式.
字符串: aaaaaaaaaaaaaaaaaaaa ; 20 个 a

表达式1 : (?i)^[0-9A-Z]([-.\w]*[0-9A-Z])*

匹配结果(标志 1) : [0]aaaaaaaaaaaaaaaaaaa ; 返回 19 个 a

表达式1分析:

模式 | 子模式 | 说明
(?i) |  | 启动不区分大小写匹配.
^ |  | 从字符串开头开始匹配.
[0-9A-Z] |  | 匹配一个字母或数字字符.
([-.\w]*[0-9A-Z])* |  | 匹配以下 0 个或多个下列子模式的组合. 这是第一个捕获组.
 | [-.\w]* | 匹配 0 个或多个 连字符, 或句号, 或字母字符 .
 | [0-9A-Z] | 匹配一个字母或数字字符.

表达式2 : (?i)[0-9A-Z][-.\w]*(?<=[0-9A-Z])

匹配结果(标志 1) : [0]aaaaaaaaaaaaaaaaaaaa ; 返回 20 个 a

表达式2分析

模式 | 说明
(?i) | 启动不区分大小写匹配.
^ | 从字符串开头开始匹配
[0-9A-Z] | 匹配一个字母或数字字符.
[-.\w]* | 匹配 0 个或多个连字符, 或句号, 或字母字符.
(?<=[0-9A-Z]) | 回顾最后一个匹配的字符, 如果该字符是字母数字字符, 则继续匹配. 请注意, 字母数字字符是由句号, 连字符和所有单词字符构成的集合的子集.

预测先行断言

包括两个语言元素 (?=断言模式) 和 (?!断言模式), 它们与输入字符串中的后面一个或多个字符匹配. 这两个语言元素都是零宽度断言; 它们通过断言模式而不是前移或回溯来确定当前字符之后紧挨着的一个或多个字符是否匹配.

(?=断言模式) 是正预测先行断言; 当前位置之后的一个或多个字符必须与断言模式匹配.
(?!断言模式)是负预测先行断言; 当前位置之后的一个或多个字符不得与断言模式匹配.
当断言模式为下一个断言模式的子集时, 正预测先行断言和负预测先行断言都最为有用.

下面示例使用两个可验证完全限定类型名称的等效正则表达式模式. 第一个模式由于过多使用回溯, 性能极差. 第二个模式通过将嵌套的限定符替换为正预测先行断言来修改第一个正则表达式.

字符串 : aaaaaaaaaaaaaaaaaaaa ; 22 个字符 a

表达式1 : (?i)^(([A-Z]\w*)+\.)*[A-Z]\w*$

测试标志 3 匹配失败, 耗时 205ms

表达式分析:

模式 | 子模式 | 说明
(?i) |  | 启动不区分大小写匹配.
^ |  | 从字符串开头开始匹配.
(([A-Z]\w*)+\.)* |  | 对后跟零个或多个单词字符, 句点的字母字符 (A-Z) 匹配一次或多次
 | ([A-Z]\w*) | 匹配任意一个 A-Z 字母后跟的单词字符的 0 次或多次.
 | +\. | 匹配上模式捕获值的 1 次或多次, 再后跟一个句号.
 | )* | 匹配上模式捕获值的 0 次或多次
[A-Z]\w* |  | 匹配任意一个 A-Z 字母后跟的单词字符的 0 次或多次.
$ |  | 在输入字符串末尾结束匹配

表达式2 : (?i)^((?=[A-Z])\w+\.)*[A-Z]\w*$ 使用正预测先行断言

测试标志 3 匹配失败, 耗时 0.062ms

表达式2分析:

模式 | 子模式 | 说明
(?i) |  | 启动不区分大小写模式.
^ |  | 从字符串开头开始匹配
((?=[A-Z])\w+\.)* |  | 匹配对象分述如下:
 | (?=[A-Z]) | 正预测先行断言. 匹配任意一个 A-Z 范围内的字母.
 | \w+\. | 匹配 1 或多个单词字符, 并后跟一个句点.
 | )* | 匹配上模式捕获值的 0 次或多次.
[A-Z]\w* |  | 0 次或多次匹配任意一个 A-Z 范围内字母
$ |  | 在输入字符串末尾结束匹配


非回溯子表达式 (?>子表达式 )

非回溯子表达式也称为一个贪婪的子表达式, 子表达式为任何有效的正则表达式模式.

通常, 如果正则表达式包含一个可选匹配模式, 并且可选模式不成功的话, 正则表达式引擎可以在多个方向上分支, 以将输入的字符串与某种模式进行匹配. 如果未找到第一个分支的匹配项, 则正则表达式引擎可以使用备份的第一个匹配项的点, 并尝试使用第二个分支的匹配项. 此过程可继续进行, 直到尝试所有分支. 这就是回溯

(?>子表达式 ) 禁用回溯. 正则表达式引擎将在输入字符串中匹配尽可能多的字符. 在没有任何进一步匹配可用时, 它将不回溯尝试可选模式匹配. (也就是说, 非回溯仅仅匹配由非回溯子表达式匹配的字符串; 不会尝试匹配与基于该子表达式其后跟随的任何该子表达式. )

如果你知道回溯不会成功, 则建议使用此选项. 防止正则表达式引擎执行不需要的搜索, 以提高搜索性能.

下面的示例回溯与非回溯如何修改模式匹配的结果. 回溯能匹配单词边界后的一系列重复(相同)字符, 但非回溯则不会匹配.

字符串: cccd, aaad, aaaa

回溯表达式: (\w)\1+.\b

匹配结果(标志 4):
[0]=> [0]cccd
[1]=> [0]aaad
[2]=> [0]aaaa -- 回溯匹配的结果, 非回溯表达式则不会匹配.

非回溯表达式: (?>(\w)\1+).\b

匹配结果(标志 4):
[0]=> [0]cccd
[1]=> [0]aaad

表达式分析:

模式 | 说明
(?>(\w)\1+) | 非回溯定义. 匹配一个或多个有重复字符的单词, 但不执行回溯 ( 不匹配单词边界上的最后一个单词 aaaa ).
(\w) | 匹配一个单词字符. 重复匹配到单词边界结束一个匹配过程 .
\1+ | 一次或多次匹配 (\w) 捕获的子字符值. 并保存到捕获组 \1 .
. | 匹配任意字符.
\b | 在单词边界处结束匹配.

以下示例分别使用 2 个正则表达式模式匹配方法显示匹配信息.

第一个方法调用 \b\(?((\w+),?\s?)+[\.!?]\)? 使用有关已捕获的子字符串的信息完全填充捕获收集和集合对象.

第二个方法使用 \b\(?((?>\w+),?\s?)+[\.!?]\)? 设置非回溯的捕获调用, 所以它不会捕获有关组的信息.

字符串: This is the first sentence. Is it the beginning of a literary masterpiece? I think not. Instead, it is a nonsensical paragraph

回溯表达式: \b\(?((\w+),?\s?)+[\.!?]\)?

匹配结果(标志 4): 返回 12 项
[0]=> [0]This is the first sentence!
[0]=> [1]sentence
[0]=> [2]sentence 非回溯表达式不会匹配.
[1]=> [0]Is it the beginning of a literary masterpiece?
[1]=> [1]masterpiece
[1]=> [2]masterpiece 非回溯表达式不会匹配.
[2]=> [0]I think not.
[2]=> [1]not
[2]=> [2]not 非回溯表达式不会匹配.
[3]=> [0]Instead, it is a nonsensical paragraph.
[3]=> [1]paragraph
[3]=> [2]paragraph 非回溯表达式不会匹配.

非回溯表达式: \b\(?((?>\w+),?\s?)+[\.!?]\)?

匹配结果(标志 4): 返回 8 项
[0]=> [0]This is the first sentence!
[0]=> [1]sentence
[1]=> [0]Is it the beginning of a literary masterpiece?
[1]=> [1]masterpiece
[2]=> [0]I think not.
[2]=> [1]not
[3]=> [0]Instead, it is a nonsensical paragraph.
[3]=> [1]paragraph

非回溯表达式分析:

模式 | 子模式 | 说明
\b |  | 在单词边界处开始.
\(? |  | 匹配左括号 “(” 的零或一个匹配项. 源字符串没有 ( 符号, 但测试添加一个 ( 符号, 也不能返回匹配 ?
((?>\w+),?\s?)+ |  | 非回溯定义 (?> . 一次或多次匹配以下子模式的匹配组合.
 | (?>\w+),? | 匹配一个或多个单词字符, 后跟零或一个逗号. 当匹配单词字符不回溯
 | \s? | 匹配零个或一个空白字符.
[\.!?]\)? |  | 与后无右括号或三个标点符号 . ! ? 中的一个后跟一个右括号 “)” 的匹配


表达式的递归匹配: (?R) 或 (?x)

相对于反向引用来说, 反向引用是在匹配过程中对匹配到的字符串内容进行引用, 而递归匹配是对表达式进行引用. 有时我们需要用正则表达式来分析一个计算式中的括号配对情况. 比如使用表达式 \( [^)]* \) 或者 \( .*? \) 可以匹配一对小括号. 但是如果括号内还嵌有一层括号的话 , 如 ( ( ) ) , 则这种写法将不能正确匹配, 得到的结果是 ( ( ) . 类似情况的还有 HTML 中支持嵌套的标签如 <font> </font> 等.

表达式使用 (?R) 或 (?x)(x=组编号) 递归进入整个正则表达式. 具体格式如下表:

格式 | 说明 | 格式 | 说明
(?R) | 对整个表达式的递归引用 | (?R1) 或 (?R2) | 对指定分组的递归引用.
(?1) 或 (?2) | 对指定分组的递归引用. | (?R<named>) 或 (?R'named') | 对指定命名分组的递归引用

下面示例匹配嵌套未知层次的 "小括号对" :

字符串: If StringInStr(FileGetAttrib($current & "\" & $file), "D") And ($file <> "." Or $file <> "..")

表达式: \(([^()]|(?R))*\)

匹配结果(标志 4):
[0]=> [0](FileGetAttrib($current & "\" & $file), "D")
[0]=> [1]"
[1]=> [0]($file <> "." Or $file <> "..")
[1]=> [1]"

表达式分析:

模式 | 子模式 | 说明
\( |  | 转义字符 ( 为本身原意字符 , 匹配一个左园括号 .
([^()]|(?R)) |  | 两个选项的可选表达式 , 分述如下 :
 | [^()] | 选项 1 , 负字符组 . 匹配一个排除左 , 右园括号的其它任意字符
 | | | 选项分隔符 .
 | (?R) | 选项 2 , 递归进入整个正则表达式 .
* |  | 0 次或多次匹配选项表达式的结果匹配项 .
\) |  | 转义字符 ) 为本身原意字符 , 匹配一个右园括号 .

几个正在表达式递归示例模式:

表达式 | 等效的表达式1 | 等效的表达式2 | 可以匹配
(\w)(?1) | (\w)(\w) |  | ab
(?1)(\w(?2))(\d) | (?1)(\w(\d))(\d) | (\w(\d))(\w(\d))(\d) | a1b23
(\w(?1)?) | (\w(\w(?1)?)?) | (\w+) | ghjk5……
\(([^()]|(?R))*\) | \(([^()]|\(([^()]|(?R))*\))*\) |  | (a*(c+2))


正则表达式替换

AutoIt 的替换过程由函数 StringRegExpReplace() 完成, 函数除明确指定替换的文本字符串外, 还支持 \0 - \9 或 $0 - $9 格式使用正则表达式的捕获组内容进行替换.

替换元素和替换模式

替换是函数 StringRegExpReplace() 模式中唯一可识别的特殊构造. 与任何字符匹配的其他正则表达式语言元素(包括字符转义和句点 .)均不受支持. 同样, 替换语言元素只能在替换模式中识别, 并且在正则表达式模式中永远无效.

可以出现在 StringRegExpReplace() 函数 "替换" 参数的可识别字符是 \ 或 $ 字符, 尽管它在每个上下文中具有不同的含义. 在正则表达式模式中, $ 是与字符串的末尾匹配的定位点. 在替换模式中, $ 指示替换的开头.

对于类似于正则表达式中替换模式的功能, 使用反向引用. 有关反向引用的更多信息, 请参见反向引用构造.

使用组编号替换: $组编号 或 \组编号

$组编号 语言元素包括替换字符串中 组编号 捕获组所匹配的最后一个子字符串, 其中组编号是捕获组的索引. 例如, 替换模式 $1 指示匹配的子字符串将由捕获的第一个组替换.有关已编号的捕获组的详细信息, 请参阅正则表达式中的分组构造.

$ 后面的所有数字解释为属于组编号组. 如果这不是你想要的结果, 可改为命名组替换. 例如, 可以使用替换字符串 ${1}1 而不是 $11 来将替换字符串定义为带数字 1 的首个捕获组的值.有关详细信息, 请参阅使用命名组替换.

没有使用 (?<name>) 语法显式分配名称的捕获组从左到右进行编号(从 1 开始). 命名组也从左到右进行编号, 但以最后一个未命名组的索引大 1 的值开始. 例如, 在正则表达式 (\w)(?<digit>\d) 中, digit 命名组的索引为 2.

如果组编号不是正则表达式模式中定义的有效捕获组, $组编号将被解释为用于替换每个匹配项的文本字符序列.

下面的示例使用 $组编号 替换去除十进制值中的货币符号.它移除在货币值的开头或末尾找到的货币符号, 并识别两个最常见的小数点分隔符(“.”和“,”).

字符串: $16.32 12.19 £16.29 €18.29 €18,29

表达式: \p{Sc}*(\s?\d+[.,]?\d*)\p{Sc}*

匹配结果(标志 3):
[0]16.32
[1] 12.19
[2]16.29
[3]18.29
[4]18,29

替换: StringRegExpReplace("$16.32 12.19 £16.29 €18.29 €18,29", '\p{Sc}*(\s?\d+[.,]?\d*)\p{Sc}*', '$1')

替换结果(替换参数为 $1) : 16.32 12.19 16.29 18.29 18,29

表达式分析:

模式 | 子模式 | 说明
\p{Sc}* |  | 匹配 0 个或多个货币符号字符.
(\s?\d+[.,]?\d*) |  | 匹配内容分述如下. 这是第一个捕获组. 因为替换模式为 $1, 所以将整个匹配的子字符串替换为此捕获组.
 | \s? | 匹配零个或一个空白字符.
 | d+ | 匹配一个或多个十进制数字.
 | [.,]? | 匹配 0 个或一个句点或逗号.
 | \d* | 匹配0 个或多个十进制数字.
\p{Sc}* |  | 匹配 0 个或多个货币符号字符.

使用 \组编号 替换

下面的示例标识字符串中的重复单词. (?i) 选项用于确保大小写不同但其他内容都相同的单词被认为是重复的.

字符串: The the dog jumped over the fence fence

表达式: (?i)\b(\w+)\s\1\b

匹配结果(标志 4):
[0]=> [0]The the
[1]=> [0]fence fence

替换: StringRegExpReplace("The the dog jumped over the fence fence", '(?i)\b(\w+)\s\1\b', '\1')

替换结果(替换参数为 \1 ): The dog jumped over the fence

表达式分析:

模式 | 说明
(?i) | 不区分大小写匹配. 确保大小写不同但其他内容都相同的单词被认为是重复的.
\b | 在单词边界处开始匹配.
(\w+) | 匹配一个或多个单词字符. 这是第一个捕获组.
\s | 与空白字符匹配.
\1 | 与第一个捕获组匹配.
\b | 在单词边界处结束匹配.