快速入门
教程
工具和语言
示例
参考
书籍评论
正则表达式工具
grep
PowerGREP
RegexBuddy
RegexMagic
通用应用程序
EditPad Lite
EditPad Pro
语言和库
Boost
Delphi
GNU (Linux)
Groovy
Java
JavaScript
.NET
PCRE (C/C++)
PCRE2 (C/C++)
Perl
PHP
POSIX
PowerShell
Python
R
Ruby
std::regex
Tcl
VBScript
Visual Basic 6
wxWidgets
XML Schema
Xojo
XQuery 和 XPath
XRegExp
数据库
MySQL
Oracle
PostgreSQL
本网站上的更多内容
简介
正则表达式快速入门
正则表达式教程
替换字符串教程
应用程序和语言
正则表达式示例
正则表达式参考
替换字符串参考
书籍评论
可打印 PDF
关于本网站
RSS Feed 和博客
RegexBuddy—The best regex editor and tester for PCRE2 users!

PCRE2 开源正则表达式库

PCRE2 是 Perl 兼容正则表达式版本 2 的简称。它是广受欢迎的 PCRE 库的继任者。两者都是由 Philip Hazel 用 C 编写的开源库。

第一个 PCRE2 版本的版本号为 10.00,以便与之前的 PCRE 8.36 明确区分。PCRE 8.37 至 8.44 以及任何未来的 PCRE 版本仅限于错误修复。新功能仅添加到 PCRE2 中。如果您正在进行新的开发项目,您应该考虑使用 PCRE2 而不是 PCRE。但对于已经使用 PCRE 的现有项目,最好坚持使用 PCRE。从 PCRE 迁移到 PCRE2 需要对您的源代码进行重大更改。这样做的唯一真正原因是使用新的搜索和替换功能。

PHP 7.3.0 从 PCRE 迁移到 PCRE2,但没有使用新的 PCRE2 搜索和替换。它继续使用 PHP 自身的替换文本语法。

R 4.0.0 也将其 grep 和相关函数从 PCRE 迁移到 PCRE2。它的 subgsub 函数继续使用 R 自身的替换文本语法。

PCRE2 10.00 至 10.34 和 PCRE 8.36 至 8.44 支持的正则表达式语法几乎相同。因此,本网站上的 正则表达式教程 中关于 PCRE(或特别是 PCRE 版本 8.36 至 8.44)的所有内容也适用于 PCRE2。PCRE2 仅在与 PCRE 不同的几个特定领域中提及。

正则表达式语法有一个新的版本检查条件。该语法看起来很像 检查命名反向引用的条件,但包含等号(和捕获组名称中不允许的其他符号)使其成为原始 PCRE 中的语法错误。在所有版本的 PCRE2 中,(?(VERSION>=10.00)yes|no) 在字符串 yesno 中匹配 yes。您可以对“yes”和“no”部分使用任何有效的正则表达式。如果版本检查成功,则尝试“yes”部分。否则,尝试“no”部分。这完全就像一个正常的条件,根据捕获组是否参与匹配来评估竖线之前或之后的哪一部分。

您可以使用 >= 来检查最低版本,或使用 = 来检查特定版本。 (?(VERSION=10.00)yes|no) 在 PCRE2 10.00 中匹配 yes。它在 PCRE2 10.10 及所有更高版本中匹配 no。省略次要版本号与指定 .00 相同。因此,(?(VERSION>=10)yes|no) 在所有版本的 PCRE2 中匹配 yes,但 (?(VERSION=10)yes|no) 仅在 PCRE2 10.00 中匹配 yes。如果您指定次要版本号,则应在小数点后使用两位数字。从版本 10.21 开始,三个或更多位数字将出错。版本 10.21 还更改了对单数字的解释,包括那些以零开头的数字。由于第一个版本是 10.00,第二个版本是 10.10,因此无需检查单数字。如果您指定次要版本号,则不能省略点。 (?(VERSION>=1000)yes|no) 检查版本 1000.00 或更高版本。

此版本检查条件主要适用于通过基于 PCRE2 的应用程序或嵌入 PCRE2 但不公开其所有函数调用的编程语言间接使用 PCRE2 的人员。它允许他们找出应用程序使用的 PCRE2 版本。如果您正在使用 PCRE2 C 库开发应用程序,那么您应该使用函数调用来确定 PCRE2 版本

char version[255];
pcre2_config(PCRE2_CONFIG_VERSION, version);

UTF-8、UTF-16 或 UTF-32

在原始 PCRE 库中,UTF-16 和 UTF-32 支持在更高版本中通过带有 pcre16_ 和 pcre32_ 前缀的其他函数添加。在 PCRE2 中,所有函数都以 pcre2_ 为前缀,并以 _8、_16 或 _32 为后缀,以选择 8 位、16 位或 32 位代码单元。如果您从源代码编译 PCRE2,则需要将 --enable-pcre2-16--enable-pcre2-32 传递给 configure 脚本,以确保 _16 和 _32 函数可用。

8 位、16 位或 32 位代码单元意味着 PCRE2 将你的字符串解释为由单字节字符、双字节字符或四字节字符组成。要使用 UTF-8、UTF-16 或 UTF-32,你需要使用具有相应代码单元大小的函数,并将 PCRE2_UTF 选项传递给 pcre2_compile 以允许字符由多个代码单元组成。UTF-8 字符由 1 到 4 个字节组成。UTF-16 字符由 1 或 2 个字组成。

如果你想在没有任何后缀的情况下调用 PCRE2 函数,如下所示,那么你需要将 PCRE2_CODE_UNIT_WIDTH 定义为 8、16 或 32,以使没有后缀的函数使用 8 位、16 位或 32 位代码单元。在包含库之前执行此操作,如下所示

#define PCRE2_CODE_UNIT_WIDTH 8
#include "pcre2.h"

没有后缀的函数始终使用你定义的代码单元大小。带有后缀的函数仍然可用。因此,你的应用程序可以使用具有所有三个代码单元大小的正则表达式。但重要的是不要将它们混淆。如果需要将相同的正则表达式与 UTF-8 和 UTF-16 字符串匹配,那么你需要使用 pcre_compile_8 和 pcre_compile_16 编译它两次,然后使用相应的 pcre_match_8 和 pcre_match_16 函数使用已编译的正则表达式。

使用 PCRE2

使用 PCRE2 比使用 PCRE 复杂一些。使用 PCRE2,你必须使用各种类型的上下文来传递某些编译或匹配选项,例如换行符处理。在 PCRE 中,这些选项可以在编译或匹配时直接作为选项位传递。

在使用正则表达式之前,需要将其转换为二进制格式以提高效率。为此,只需调用 pcre2_compile(),并将你的正则表达式作为字符串传递。如果字符串以空终止,你可以将 PCRE2_ZERO_TERMINATED 作为第二个参数传递。否则,将代码单元中的长度作为第二个参数传递。对于 UTF-8,这是以字节为单位的长度,而对于 UTF-16 或 UTF-32,这是以字节为单位的长度除以 2 或 4。第三个参数是一组与二进制或组合的选项。你应该包含 PCRE2_UTF 以获得适当的 UTF-8、UTF-16 或 UTF-32 支持。如果你省略它,你将获得纯 8 位、UCS-2 或 UCS-4 字符处理。其他常见选项包括 PCRE2_CASELESS、PCRE2_DOTALL、PCRE2_MULTILINE 等。第四个和第五个参数接收错误条件。最后一个参数是上下文。除非你需要特殊的换行符处理,否则传递 NULL。该函数返回指向它分配的内存的指针。当你完成正则表达式时,你必须使用 pcre2_code_free() 释放它。

如果你需要非默认换行符处理,你需要调用 pcre2_compile_context_create(NULL) 来创建一个新的编译上下文。然后调用 pcre2_set_newline() 传递该上下文和一个选项,如 PCRE2_NEWLINE_LF 或 PCRE2_NEWLINE_CRLF。然后将此上下文作为最终参数传递给 pcre2_compile()。你可以对任意数量的正则表达式编译重用相同的上下文。当你完成时,调用 pcre2_compile_context_free()。请注意,在原始的 PCRE 中,你可以直接将 PCRE_NEWLINE_LF 等传递给 pcre_compile()。这在 PCRE2 中不起作用。如果你将 PCRE2_NEWLINE_LF 等传递给 pcre2_compile(),PCRE2 不会抱怨。但这样做没有任何效果。你必须使用匹配上下文。

在你使用已编译的正则表达式在字符串中查找匹配项之前,你需要调用 pcre2_match_data_create_from_pattern() 来分配内存以存储匹配结果。将已编译的正则表达式作为第一个参数传递,将 NULL 作为第二个参数。该函数返回一个指向它分配的内存的指针。当你完成匹配数据后,你必须使用 pcre2_match_data_free() 释放它。你可以对 pcre2_match() 的多次调用重用相同的匹配数据。

要查找匹配项,请调用 pcre2_match() 并传递已编译的正则表达式、主题字符串、整个字符串的长度、匹配尝试必须开始的字符的偏移量、匹配选项、指向匹配数据对象的指针以及 NULL 作为上下文。长度和起始偏移量以代码单元为单位,而不是字符。当匹配成功时,该函数返回一个正数。PCRE2_ERROR_NOMATCH 表示未找到匹配项。任何其他非正返回值表示错误。可以使用 pcre2_get_error_message() 获取错误消息。

要找出字符串的哪一部分匹配,请调用 pcre2_get_ovector_pointer()。这会返回一个指向 PCRE2_SIZE 值数组的指针。你不需要释放此指针。当你调用 pcre2_match_data_free() 时,它将变为无效。该数组的长度是 pcre2_match() 返回的值。数组中的前两个值是整体匹配的开始和结束。第二对是第一个捕获组的匹配,依此类推。如果你的正则表达式具有命名的捕获组,请调用 pcre2_substring_number_from_name() 以获取组号。

如果你只想获取匹配的文本,你可以使用方便的函数,如 pcre2_substring_copy_bynumber() 或 pcre2_substring_copy_byname()。传递捕获组的编号或名称,或传递零以进行整体匹配。使用 pcre2_substring_free() 释放结果。如果结果不需要以零结尾,你可以使用 pcre2_substring_get_bynumber() 和 pcre2_substring_get_byname() 获取指向原始主题字符串中匹配项开始位置的指针。pcre2_substring_length_bynumber() 和 pcre2_substring_length_byname() 为你提供匹配项的长度。

PCRE2 不会提供一个函数,该函数会提供字符串中正则表达式的全部匹配项。它永远不会返回多于第一个匹配项。要获得第二个匹配项,请再次调用 pcre2_match(),并将 ovector[1](第一个匹配项的结尾)作为第二个匹配尝试的起始位置传递。如果第一个匹配项的长度为零,请将 PCRE2_NOTEMPTY_ATSTART 与传递给 pcre2_match() 的选项一起包含在内,以避免再次找到相同的零长度匹配项。这与在调用之前增加起始位置不同。使用 PCRE2_NOTEMPTY_ATSTART 传递前一个匹配项的结尾可能会导致在相同位置找到非零长度匹配项。

替换匹配项

PCRE 愿望清单上永远存在的最重要的一项可能就是搜索和替换功能。PCRE2 终于实现了。替换字符串语法相当简单。不过,它与 Perl 并不兼容。反向引用可以指定为 $group${group},其中“group”是组的名称或编号。整体匹配项是组号零。要在替换中添加文字美元符号,你需要将其加倍。任何不属于有效反向引用的单个美元符号都是一个错误。与 Python 类似,但与 Perl 不同,PCRE2 将对不存在的组的反向引用对不参与的组的反向引用视为错误。反斜杠是文字。

在替换匹配项之前,你需要使用 pcre2_compile() 编译正则表达式。你可以将相同的已编译正则表达式用于正则表达式匹配和正则表达式替换。你不需要匹配数据对象进行替换。

调用 pcre2_substitute() 并将已编译的正则表达式、主题字符串、主题字符串的长度、正则表达式匹配应开始的字符串中的位置以及匹配选项传递给它。你可以将 PCRE2_SUBSTITUTE_GLOBAL 与匹配选项一起包含在内,以替换起始位置之后的全部匹配项,而不仅仅是第一个匹配项。下一个参数用于匹配数据和匹配上下文,它们都可以设置为 NULL。然后传递替换字符串和替换字符串的长度。最后传递一个指向应存储结果字符串的缓冲区的指针,以及一个指向保存缓冲区大小的变量的指针。缓冲区需要有空间容纳终止零。所有长度和偏移量都以代码单元为单位,而不是字符。

pcre2_substitute() 返回被替换的正则表达式匹配项的数量。零表示未找到匹配项。此函数永远不会返回 PCRE2_ERROR_NOMATCH。负数表示发生错误。调用 pcre2_get_error_message() 以获取错误消息。保存缓冲区大小的变量会更新,以指示写入缓冲区的字符串的长度,不包括终止零。(终止零会被写入。)

扩展替换字符串语法

从版本 10.21 开始,PCRE2 提供了扩展替换字符串语法,你可以在调用 pcre2_substitute() 时将 PCRE2_SUBSTITUTE_EXTENDED 与匹配选项一起包含在内以启用该语法。最大的不同在于反斜杠不再是文字。反斜杠后跟一个不是字母或数字的字符会转义该字符。因此,你可以使用其他反斜杠转义美元符号和反斜杠,以取消其特殊含义。如果你希望在替换中使用文字反斜杠,则必须使用另一个反斜杠对其进行转义。反斜杠后跟一个数字是一个错误。反斜杠后跟一个字母是一个错误,除非该组合形成替换字符串标记。

\a\e\f\n\r\t 是通常的 ASCII 控制字符转义。值得注意的是,缺少 \b\v\x0\xF\x00\xFF 是十六进制转义。\x{0}\x{10FFFF} 插入 Unicode 代码点。\o{0}\o{177777} 是八进制转义。

大小写转换 也受支持。语法与 Perl 相同,但行为不同。Perl 允许您将 \u\l\L\U 结合使用,以使一个字符大写或小写,而其余字符则相反。使用 PCRE2,任何大小写转换转义都会取消前面的转义。因此,您不能将它们组合在一起,甚至 \u\l 也会结束 \U\L 的运行。

条件 使用新发明的语法受支持,该语法扩展了反向引用的语法。${group:+matched:unmatched} 在组参与时插入 matched,在组不参与时插入 unmatched。您可以在两个备选方案中使用完整的替换字符串语法,包括其他条件。

大小写转换贯穿条件。条件之前生效的任何大小写转换也适用于条件。如果条件在实际使用的条件部分包含其自身的大小写转换转义,那么这些转义在条件之后仍然有效。因此,您可以使用 ${1:+\U:\L}${2} 在第一个组参与时以大写插入第二个捕获组匹配的文本,在第一个组不参与时以小写插入文本。

| 快速入门 | 教程 | 工具和语言 | 示例 | 参考 | 书籍评论 |

| grep | PowerGREP | RegexBuddy | RegexMagic |

| EditPad Lite | EditPad Pro |

| Boost | Delphi | GNU (Linux) | Groovy | Java | JavaScript | .NET | PCRE (C/C++) | PCRE2 (C/C++) | Perl | PHP | POSIX | PowerShell | Python | R | Ruby | std::regex | Tcl | VBScript | Visual Basic 6 | wxWidgets | XML Schema | Xojo | XQuery & XPath | XRegExp |

| MySQL | Oracle | PostgreSQL |