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

PHP正则表达式:捕获重复命名递归的所有匹配项

解决PHP正则中重复命名递归的所有匹配项捕获问题

嘿,我来帮你搞定这个PHP正则的递归捕获难题!你现在的需求是要捕获递归结构里所有重复的命名组匹配项,默认情况下PHP的PCRE会覆盖之前的匹配值,所以得调整正则写法和匹配方式。

核心问题分析

PHP的PCRE引擎默认情况下,同一个命名捕获组如果被多次匹配(不管是递归还是循环),最后一次匹配会覆盖之前的结果。要捕获所有实例,我们需要结合递归子组定义、(?J)修饰符(允许重复命名组)和正确的preg_match_all参数。

调整后的正则表达式

针对你给出的原正则,我调整了结构来支持递归捕获所有parameter_set实例:

/(?J)
\(
  (?# Expression start)
  (?<optgroup_start>\()
  (?# Parameter group start - 递归捕获所有参数项)
  (?<parameter_set>\[(?:[a-z0-9]+)\])
  (?:,*\s*(?&parameter_set))*
  (?<optgroup_end>\))
  ,*\s*
  (?:
    "(?<options_scalar>.*)"
    |
    (?<options_complex>.*)
  )
|
(?<simple_parameter_set>
  (?<parameter_set>\[(?:[a-z0-9]+)\])
  (?:,*\s*(?&parameter_set))*
)
/xg

关键修改点:

  • 添加(?J)修饰符:允许正则中重复使用同一个命名组名(比如parameter_set在两个分支都出现)。
  • 重构parameter_set为递归结构:(?<parameter_set>\[(?:[a-z0-9]+)\])(?:,*\s*(?&parameter_set))*,这样每个[xxx]都会被单独捕获为parameter_set的一个实例。
  • 添加/x修饰符:忽略正则里的空白和注释,让结构更清晰;/g全局匹配,捕获所有符合的结构。

如何捕获所有匹配项

使用preg_match_all配合PREG_PATTERN_ORDER参数,这样命名组的所有捕获实例会被整理成数组:

$pattern = '/(?J)\( (?# Expression start) (?<optgroup_start>\() (?# Parameter group start - 递归捕获所有参数项) (?<parameter_set>\[(?:[a-z0-9]+)\]) (?:,*\s*(?&parameter_set))* (?<optgroup_end>\)) ,*\s* (?: "(?<options_scalar>.*)" | (?<options_complex>.*) ) | (?<simple_parameter_set> (?<parameter_set>\[(?:[a-z0-9]+)\]) (?:,*\s*(?&parameter_set))* )/xg';
$subject = '([foo], [bar], [baz]), "opt1" | ([qux], [quux])';

preg_match_all($pattern, $subject, $matches, PREG_PATTERN_ORDER);

// 输出所有parameter_set的捕获实例
print_r($matches['parameter_set']);

这段代码会输出所有匹配到的[foo]、[bar]、[baz]、[qux]、[quux],每个都是parameter_set数组里的单独元素。

兼容旧版本PHP(<7.3)

如果你还在使用PHP 7.3之前的版本,(?J)修饰符不被支持,那可以改用匿名子组+全局匹配的方式,或者给不同分支的组起不同名字,然后合并结果:

/
\(
  (?<optgroup_start>\()
  (?<param1>\[(?:[a-z0-9]+)\])
  (?:,*\s*(?<param2>\[(?:[a-z0-9]+)\]))*
  (?<optgroup_end>\))
  ,*\s*
  (?: "(?<options_scalar>.*)" | (?<options_complex>.*) )
|
(?<simple_param1>\[(?:[a-z0-9]+)\])
(?:,*\s*(?<simple_param2>\[(?:[a-z0-9]+)\]))*
/xg

然后在PHP里合并$matches['param1']、$matches['param2']、$matches['simple_param1']等数组,得到所有捕获项。不过这种方式不够优雅,还是建议升级到PHP 7.3+使用(?J)方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:44:06