如何用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
相关产品推荐
相关产品推荐

