好的,我来详细介绍 PCRE(Perl Compatible Regular Expressions)正则库及用法。
一、PCRE 简介
PCRE(Perl Compatible Regular Expressions)是一个用 C 语言编写的正则表达式库,它实现了与 Perl 语言几乎完全兼容的正则语法。
它常被应用在各种项目中,比如 PHP、Apache HTTP Server、Nginx、Git 等,来提供高性能的正则匹配能力。
相较于 POSIX 正则,PCRE 功能更强大,支持:
- 高级语法(如环视、递归、条件分支)
- Unicode 支持
- 高效的 DFA/NFA 混合引擎
二、PCRE 的安装与使用
1. 安装(Linux 为例)
大部分 Linux 发行版都可以直接安装:
sudo apt-get install libpcre3 libpcre3-dev # Debian/Ubuntu
sudo yum install pcre pcre-devel # CentOS/RHEL
编译时链接:
gcc test.c -lpcre
2. 基本 API(C 语言)
使用 PCRE 库主要分为 编译正则 → 执行匹配 → 释放资源 三步。
(1)编译正则
const char *error;
int erroffset;
pcre *re = pcre_compile(
"pattern", // 正则表达式
0, // 编译选项
&error, // 错误信息
&erroffset, // 出错位置
NULL // 字符表 (NULL = 默认)
);
(2)执行匹配
int ovector[30]; // 存储匹配位置 (start, end)
int rc = pcre_exec(
re, // 编译后的正则
NULL, // 可选的匹配加速数据
subject, // 输入文本
strlen(subject),
0, // 起始偏移
0, // 匹配选项
ovector, // 输出数组
30 // 输出数组大小
);
rc > 0
表示匹配成功,返回捕获组个数rc == 0
表示匹配成功但捕获组太少rc < 0
表示失败(PCRE_ERROR_NOMATCH
等)
(3)释放资源
pcre_free(re);
三、常用功能示例
1. 基本匹配
const char *pattern = "hello";
const char *subject = "hello world";
会匹配开头的 “hello”。
2. 捕获分组
(\d{4})-(\d{2})-(\d{2})
可匹配 2025-09-20
,并捕获:
$1 = 2025
$2 = 09
$3 = 20
3. 环视(零宽断言)
(?<=@)[A-Za-z0-9_]+
匹配邮箱中 @
后的用户名。
4. 非贪婪匹配
<.*?>
匹配最短的 HTML 标签,而不是整个字符串。
5. 条件匹配
(?(1)then|else)
如果第 1 个捕获组匹配成功,则匹配 then
,否则匹配 else
。
四、PCRE 的常见应用
- Web 服务器:Nginx、Apache Rewrite 规则
- 文本处理:grep、sed 的增强版本
- 编程语言绑定:PHP 的
preg_match
系列函数就是基于 PCRE - 安全领域:Snort IDS/IPS 中基于 PCRE 进行恶意流量检测
五、与 PCRE2 的区别
- PCRE(旧版):功能稳定,但已停止主要开发(安全维护为主)
- PCRE2(新版):重构版本,API 更清晰,性能和 Unicode 支持更好
pcre_compile
→pcre2_compile
pcre_exec
→pcre2_match
pcre_free
→pcre2_code_free
好的 👍 我给你写一个 完整的 C 语言 PCRE 匹配示例:
目标:匹配一段文本里的 Email 地址,并输出匹配结果。
示例代码:PCRE 匹配 Email
#include <stdio.h>
#include <string.h>
#include <pcre.h>
int main() {
const char *error;
int erroffset;
int ovector[30]; // 保存匹配位置
int rc;
// 正则表达式:匹配 Email 地址
const char *pattern = "([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\\.([a-zA-Z]{2,})";
const char *subject = "我的邮箱是 test.email+123@example.com,还有另一个 hello_world@domain.org";
// 1. 编译正则
pcre *re = pcre_compile(
pattern, // 正则表达式
0, // 编译选项
&error, // 错误信息
&erroffset, // 出错位置
NULL // 字符表 (NULL = 默认)
);
if (re == NULL) {
printf("PCRE 编译失败!错误: %s (位置 %d)\n", error, erroffset);
return 1;
}
// 2. 匹配文本(可多次匹配)
const char *cursor = subject;
int start_offset = 0;
while ((rc = pcre_exec(
re, // 已编译的正则
NULL, // 可选的匹配加速数据
subject, // 输入文本
strlen(subject), // 输入长度
start_offset, // 起始偏移
0, // 匹配选项
ovector, // 输出匹配位置
30 // 输出数组大小
)) >= 0) {
// 打印整个匹配
printf("找到匹配: ");
for (int i = 0; i < rc; i++) {
const char *substring_start = subject + ovector[2*i];
int substring_length = ovector[2*i+1] - ovector[2*i];
printf("[%.*s] ", substring_length, substring_start);
}
printf("\n");
// 更新起始偏移,继续寻找下一个匹配
start_offset = ovector[1];
}
if (rc == PCRE_ERROR_NOMATCH) {
printf("没有找到更多匹配。\n");
}
// 3. 释放资源
pcre_free(re);
return 0;
}
编译与运行
假设保存为 pcre_email.c
:
gcc pcre_email.c -lpcre -o pcre_email
./pcre_email
运行结果示例
找到匹配: [test.email+123@example.com] [test.email+123] [example] [com]
找到匹配: [hello_world@domain.org] [hello_world] [domain] [org]
没有找到更多匹配。
整体匹配
:完整的邮箱地址捕获组1
:用户名部分捕获组2
:域名部分捕获组3
:顶级域名
发表回复