You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中使用pcre2_substitute实现全部匹配项替换?

如何用pcre2_substitute实现全局替换?

我现在用pcre2_substitute只能替换首个匹配项,代码如下:

#define PCRE2_CODE_UNIT_WIDTH 8

#include <stdio.h>
#include <string.h>
#include <pcre2.h>
int main(int argc, char **argv)
{
    PCRE2_SPTR pattern = "(\\d+)";
    PCRE2_SPTR subject = "1 something 849 for 993";
    PCRE2_SPTR replacement = "XXX";

    pcre2_code *re;
    int errornumber;
    int i;
    int rc;

    PCRE2_SIZE erroroffset;
    PCRE2_SIZE *ovector;

    size_t subject_length;
    size_t replacement_length = strlen((char *)replacement);

    pcre2_match_data *match_data;

    subject_length = strlen((char *)subject);

    PCRE2_UCHAR output[1024] = "";
    PCRE2_SIZE outlen = sizeof(output) / sizeof(PCRE2_UCHAR);

    re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, NULL);
    if (re == NULL)
    {
        PCRE2_UCHAR buffer[256];
        pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
        printf("PCRE2 compilation failed at offset %d: %s\n", (int)erroroffset, buffer);
    }

    match_data = pcre2_match_data_create_from_pattern(re, NULL);
    rc = pcre2_substitute(re, subject, subject_length, 0, 0, match_data, NULL, replacement, 
         replacement_length, output, &outlen);
    printf("Output: %s", output);
    return 0;
}

我知道要循环调用pcre2_substitute来替换后续匹配项,但不确定怎么安全地把output作为下一次调用的subject参数传入。


实现全局替换的两种方式

方式一:使用PCRE2_SUBSTITUTE_GLOBAL标志(推荐)

不需要手动循环,直接给pcre2_substitute传入PCRE2_SUBSTITUTE_GLOBAL标志,就能一次性替换所有匹配项:

修改后的核心调用代码:

rc = pcre2_substitute(
    re,
    subject,
    subject_length,
    0,
    PCRE2_SUBSTITUTE_GLOBAL,  // 开启全局替换
    match_data,
    NULL,
    replacement,
    replacement_length,
    output,
    &outlen
);

这种方式简洁高效,是官方推荐的全局替换方案。

方式二:手动循环(适合需要自定义替换逻辑的场景)

如果必须手动循环,关键是用双缓冲区交替存储输入和输出,避免替换时覆盖未处理的输入数据。以下是完整示例:

#define PCRE2_CODE_UNIT_WIDTH 8

#include <stdio.h>
#include <string.h>
#include <pcre2.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    PCRE2_SPTR pattern = "(\\d+)";
    PCRE2_SPTR initial_subject = "1 something 849 for 993";
    PCRE2_SPTR replacement = "XXX";

    pcre2_code *re;
    int errornumber;
    int rc;
    PCRE2_SIZE erroroffset;
    pcre2_match_data *match_data;

    size_t replacement_length = strlen((char *)replacement);
    // 双缓冲区交替使用,防止输入被覆盖
    PCRE2_UCHAR buf1[1024], buf2[1024];
    PCRE2_SPTR current_subject = initial_subject;
    size_t current_length = strlen((char *)current_subject);
    PCRE2_UCHAR *output_buf = buf1;
    PCRE2_SIZE outlen;

    // 编译正则表达式
    re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, NULL);
    if (re == NULL)
    {
        PCRE2_UCHAR buffer[256];
        pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
        printf("PCRE2 compilation failed at offset %d: %s\n", (int)erroroffset, buffer);
        return 1;
    }

    match_data = pcre2_match_data_create_from_pattern(re, NULL);

    do {
        // 重置输出缓冲区
        outlen = sizeof(buf1) / sizeof(PCRE2_UCHAR);
        memset(output_buf, 0, outlen);

        // 单次替换首个匹配项
        rc = pcre2_substitute(
            re,
            current_subject,
            current_length,
            0,
            0,
            match_data,
            NULL,
            replacement,
            replacement_length,
            output_buf,
            &outlen
        );

        if (rc < 0) {
            if (rc == PCRE2_ERROR_NOMATCH) {
                // 无更多匹配,输出结果
                printf("Output: %s\n", 
                    current_subject == initial_subject ? initial_subject : 
                    (current_subject == buf1 ? buf2 : buf1));
                break;
            } else {
                // 处理其他错误
                PCRE2_UCHAR buffer[256];
                pcre2_get_error_message(rc, buffer, sizeof(buffer));
                printf("Substitute error: %s\n", buffer);
                break;
            }
        }

        // 交换输入输出缓冲区
        if (current_subject == initial_subject) {
            current_subject = output_buf;
        } else {
            current_subject = (output_buf == buf1) ? buf2 : buf1;
        }
        current_length = outlen;
        output_buf = (output_buf == buf1) ? buf2 : buf1;

    } while (1);

    // 释放资源
    pcre2_match_data_free(match_data);
    pcre2_code_free(re);

    return 0;
}

关键注意点

  • 双缓冲区交替:每次替换用一个缓冲区存输入,另一个存输出,避免数据覆盖。
  • 循环终止:当pcre2_substitute返回PCRE2_ERROR_NOMATCH时,说明没有更多匹配项,终止循环。
  • 资源释放:必须释放编译后的正则表达式和匹配数据,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Googlebot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:30:50