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

如何用PCRE2获取所有正则匹配偏移量?附修正实现

问题描述

我想要实现一个C语言函数int** text_match(const char* input, const char* pattern);,用来返回所有正则匹配结果的起止偏移量。

目前我通过迭代输入字符串并设置起始偏移量的方式完成了实现:在输入字符串的起始偏移量范围内查找匹配,获取偏移量后将起始偏移量设为匹配的结束偏移量。

但这个方法存在明显缺陷:

  • 部分模式(如^|\n|$)会导致无限匹配;
  • 即便修复了无限执行的问题,(^|\n)仍会在字符串片段开头持续匹配,把每个索引都当作匹配结果。

我尝试使用pcre2_get_ovector_count(),但在调用pcre2_match()后传入pcre2_match_data,它始终返回1而不是实际匹配数量。

请问如何直接通过PCRE2获取所有匹配偏移量,或者至少规避上述问题?


原实现(MIT许可)

int** text_match(const char* input, const char* regex){
    if(!input || !regex) return (int**)calloc(1, sizeof(int*));

    int errorcode;
    PCRE2_SIZE erroroffset;

    pcre2_code *compiled_regex = pcre2_compile((PCRE2_SPTR)regex, PCRE2_ZERO_TERMINATED, PCRE2_EXTENDED|PCRE2_UTF, &errorcode, &erroroffset, NULL);

    if(!compiled_regex) return (int**)calloc(1, sizeof(int*));
    
    pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(compiled_regex, NULL);
    
    if(!match_data){
        pcre2_code_free(compiled_regex);

        return (int**)calloc(1, sizeof(int*));
    }

    int** output = (int**)calloc(1, sizeof(int*));
    if(!output){
        pcre2_code_free(compiled_regex);
        pcre2_match_data_free(match_data);

        return (int**)calloc(1, sizeof(int*));
    }
    
    PCRE2_SIZE start_offset = 0;

    int matches_amount;
    
    size_t length_input = strlen(input);

    for(matches_amount = 0; ; matches_amount++){
        if(start_offset >= length_input) break;
    
        if(pcre2_match(compiled_regex, (PCRE2_SPTR)input, PCRE2_ZERO_TERMINATED, start_offset, 0, match_data, NULL) < 0) break;
        
        PCRE2_SIZE *offsets = pcre2_get_ovector_pointer(match_data);
        
        if(offsets == NULL) break;

        output[matches_amount] = (int*)malloc(2 * sizeof(int));
        
        if(output[matches_amount] == NULL) break;

        output[matches_amount][0] = offsets[0];
        output[matches_amount][1] = offsets[1];

        int** new_output = (int**)realloc(output, sizeof(int*) * (matches_amount + 2));
        if(new_output == NULL) break;
        output = new_output;

        if(start_offset == offsets[1]){
            start_offset++;
        }else{
            start_offset = offsets[1];
        }
    }
    
    output[matches_amount] = NULL;
    
    pcre2_code_free(compiled_regex);
    pcre2_match_data_free(match_data);

    return output;
}

修正后的实现(MIT许可)

经@ikegami指出,原实现思路正确但边缘情况检测不足,以下是修正后的函数,可自由使用:

int** text_match(const char* input, const char* regex){
    if(!input || !regex) return (int**)calloc(1, sizeof(int*));

    int errorcode;
    PCRE2_SIZE erroroffset;

    pcre2_code *compiled_regex = pcre2_compile((PCRE2_SPTR)regex, PCRE2_ZERO_TERMINATED, PCRE2_EXTENDED|PCRE2_UTF, &errorcode, &erroroffset, NULL);

    if(!compiled_regex) return (int**)calloc(1, sizeof(int*));
    
    pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(compiled_regex, NULL);
    
    if(!match_data){
        pcre2_code_free(compiled_regex);

        return NULL;
    }

    int** output = (int**)calloc(1, sizeof(int*));
    if(!output){
        pcre2_code_free(compiled_regex);
        pcre2_match_data_free(match_data);

        return NULL;
    }
    
    PCRE2_SIZE start_offset = 0;

    int matches_amount;
    
    size_t length_input = strlen(input);

    uint32_t options = 0;

    for(matches_amount = 0; ; matches_amount++){
        if(pcre2_match(compiled_regex, (PCRE2_SPTR)input, PCRE2_ZERO_TERMINATED, start_offset, options, match_data, NULL) < 0) break;
        
        PCRE2_SIZE *offsets = pcre2_get_ovector_pointer(match_data);
        
        if(offsets == NULL) break;

        output[matches_amount] = (int*)malloc(2 * sizeof(int));
        
        if(!output[matches_amount]){
            for(int i = 0; output[i]; i++) free(output[i]);
            free(output);
            pcre2_code_free_8(compiled_regex);
            pcre2_match_data_free_8(match_data);
            
            return NULL;
        }

        output[matches_amount][0] = offsets[0];
        output[matches_amount][1] = offsets[1];

        int** new_output = (int**)realloc(output, sizeof(int*) * (matches_amount + 2));
        if(!new_output){
            for(int i = 0; output[i]; i++) free(output[i]);
            free(output);
            pcre2_code_free_8(compiled_regex);
            pcre2_match_data_free_8(match_data);
            
            return NULL;
        }
        output = new_output;
        
        if(offsets[0] == offsets[1]){
            if(offsets[0] == length_input) break;
            options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
        }else{
            size_t startchar = pcre2_get_startchar(match_data);
            if(start_offset > startchar) continue;
            start_offset = startchar + 1;
            
            for(; start_offset < length_input; start_offset++){
                if((input[start_offset] & 0xc0) != 0x80) break;
            }
            
        }
    }
    
    output[matches_amount] = NULL;
    
    pcre2_code_free(compiled_regex);
    pcre2_match_data_free(match_data);

    return output;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:10:57