好的,我来详细介绍 PCRE(Perl Compatible Regular Expressions)正则库及用法


一、PCRE 简介

PCRE(Perl Compatible Regular Expressions)是一个用 C 语言编写的正则表达式库,它实现了与 Perl 语言几乎完全兼容的正则语法。
它常被应用在各种项目中,比如 PHPApache HTTP ServerNginxGit 等,来提供高性能的正则匹配能力。

相较于 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. 环视(零宽断言)

(?&lt;=@)[A-Za-z0-9_]+

匹配邮箱中 @ 后的用户名。

4. 非贪婪匹配

&lt;.*?>

匹配最短的 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_compilepcre2_compile
    • pcre_execpcre2_match
    • pcre_freepcre2_code_free

好的 👍 我给你写一个 完整的 C 语言 PCRE 匹配示例

目标:匹配一段文本里的 Email 地址,并输出匹配结果。


示例代码:PCRE 匹配 Email

#include &lt;stdio.h>
#include &lt;string.h>
#include &lt;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,              // 编译选项
        &amp;error,         // 错误信息
        &amp;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 &lt; 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:顶级域名