为何PCRE正则表达式仅能捕获19个分组?
问题:PCRE正则表达式为何仅能捕获19个分组?
我的正则表达式模式:(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)(q)(r)(s)(t)(u)(v)(w)(x)(y)(z)
匹配字符串:abcdefghijklmnopqrstuvwxyz
代码输出结果:
i_0:0 i_1:26 i_2:0 i_3:1 i_4:1 i_5:2 i_6:2 i_7:3 i_8:3 i_9:4 i_10:4 i_11:5 i_12:5 i_13:6 i_14:6 i_15:7 i_16:7 i_17:8 i_18:8 i_19:9 i_20:9 i_21:10 i_22:10 i_23:11 i_24:11 i_25:12 i_26:12 i_27:13 i_28:13 i_29:14 i_30:14 i_31:15 i_32:15 i_33:16 i_34:16 i_35:17 i_36:17 i_37:18 i_38:18 i_39:19 i_40:0 i_41:0 i_42:0 i_43:0 i_44:0 i_45:0 i_46:0 i_47:0 i_48:0 i_49:0 i_50:0 i_51:0 i_52:0 i_53:0 i_54:0 i_55:0 i_56:0 i_57:0 i_58:0 i_59:0
我的代码
#include <pcre.h> #include <iostream> pcre* _rex; pcre_extra* _rexEx; void CompileRexStr(const std::string& rex) { const char* errorinfo; int errpos = 0; _rex = NULL; _rexEx = NULL; _rex = pcre_compile(rex.c_str(), PCRE_UTF8, &errorinfo, &errpos, NULL); _rexEx = pcre_study(_rex, PCRE_STUDY_JIT_COMPILE, &errorinfo); } int main(){ std::string rex = "(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)(q)(r)(s)(t)(u)(v)(w)(x)(y)(z)"; CompileRexStr(rex); std::string str = "abcdefghijklmnopqrstuvwxyz"; int result[60] = {0}; int cur = 0; int pos = pcre_exec(_rex, _rexEx, str.c_str(), str.length(), cur, 0, result, 60); for(int i=0;i < 60; i++) { std::cout << "i_" << i << ":" << result[i] << " "; } return 0; }
解答
你的问题核心在于没有对PCRE的编译和匹配过程做错误检查,导致无法定位问题根源。以下是具体分析和解决步骤:
1. 先排查基础错误
首先在代码中添加错误检查逻辑,确认正则是否编译成功、匹配是否正常:
- 检查
pcre_compile的返回值,如果为NULL说明编译失败,打印错误信息。 - 检查
pcre_study的错误信息,排查JIT编译问题。 - 打印
pcre_exec的返回值,该值表示成功匹配到的分组总数(包含0号分组,即整个匹配结果)。
修改后的关键代码片段:
void CompileRexStr(const std::string& rex) { const char* errorinfo; int errpos = 0; _rex = NULL; _rexEx = NULL; _rex = pcre_compile(rex.c_str(), PCRE_UTF8, &errorinfo, &errpos, NULL); if (_rex == NULL) { std::cerr << "正则编译错误,位置" << errpos << ": " << errorinfo << std::endl; return; } _rexEx = pcre_study(_rex, PCRE_STUDY_JIT_COMPILE, &errorinfo); if (errorinfo != NULL) { std::cerr << "JIT编译错误: " << errorinfo << std::endl; } } int main(){ // ... 原有代码 ... int pos = pcre_exec(_rex, _rexEx, str.c_str(), str.length(), cur, 0, result, 60); std::cout << "\npcre_exec返回值(分组总数): " << pos << std::endl; // 打印捕获分组数量 int num_captures; pcre_info(_rex, NULL, &num_captures); std::cout << "正则定义的捕获分组数: " << num_captures << std::endl; // ... 原有代码 ... }
2. 可能的问题原因
- 正则编译失败:如果
pcre_compile返回NULL,说明你的正则表达式存在语法错误(但你的正则结构简单,大概率不是这个原因),或者PCRE库未正确链接。 - JIT编译问题:你使用了
PCRE_STUDY_JIT_COMPILE选项,部分环境下JIT编译可能出现异常,导致分组捕获不完整。可以尝试去掉该选项,用pcre_study(_rex, 0, &errorinfo)重试。 - PCRE库配置限制:如果你的PCRE库在编译时被手动设置了
--with-max-capture=19这类参数,会限制捕获分组的最大数量。这种情况下需要重新编译PCRE库,或者更换为PCRE2(默认支持更多分组)。 - 数组填充误解:PCRE的
result数组中,每个分组占用两个元素(起始位置和结束位置),0号分组是整个匹配结果。如果pcre_exec返回27,说明所有26个捕获分组都已成功捕获,只是你打印的数组中后面的元素未被覆盖(初始值为0),但实际前54个元素应该包含所有分组的位置信息。
3. 验证方法
先运行添加错误检查后的代码,根据输出判断:
- 如果
pcre_exec返回27,说明所有分组都已捕获,检查你打印的数组前54个元素,应该能找到分组20到26的位置(比如分组20对应索引40和41,值应为19和20)。 - 如果返回值小于27,结合
num_captures的输出,判断是编译时的分组限制,还是匹配阶段的问题。
内容的提问来源于stack exchange,提问作者Ken Zheng
相关产品推荐
相关产品推荐

