正则表达式:
/(?<nn>(?!und)[^/,&;]+)(?:,s?+)(?<vn>(?1))(?:/|&|;|und|$)s?/
应该使用preg_match_all
导致两个匹配
nn(1): Oidtmann-van Beek
vn(1): Jeanne
nn(2): Oidtmann
vn(2): Peter
关于样本串Oidtmann-van Beek, Jeanne und Oidtmann, Peter
这适用于PCRE2(PHP>=7.3(
但不是用PHP<7.3,为什么?
https://regex101.com/r/zotHZN/1/
使用PCRE无法获得预期的输出,因为(?1)
regex子例程是原子的,其模式无法回溯。
参见">PCRE2和Perl之间递归处理的差异":
10.30版本之前,PCRE2中的递归处理与Perl的不同之处在于,递归子例程调用始终被视为原子组。也就是说,一旦它匹配了一些主题字符串,就永远不会重新输入,即使它包含未经尝试的替代项,并且随后匹配失败。(历史注释:PCRE在Perl之前实现了递归。(
从10.30版本开始,递归子例程调用不再被视为原子调用。也就是说,如果模式稍后出现匹配失败,则可以重新输入它们以尝试未使用的替代方案。这现在与Perl的工作方式兼容了。如果希望子例程调用是原子调用,则必须将其显式地包含在原子组中。
因此,解决方案是使用模式本身,而不是子程序:
/(?<nn>(?!und)[^/,&;]+),s?+(?<vn>(?!und)[^/,&;]+)(?:/|&|;|und|$)s?/
注意,我仅用s?+
替换了(?:,s?+)
,因为这里的非捕获组是多余的。
我认为像/b(?<nn>(?!undb)w+(?:[-'s]+(?!undb)w+)*),s?(?<vn>(?&nn))b/u
这样更精确的模式在这里会更好。请参阅此regex演示。它将不需要任何回溯,因为w+(?:[-'s]+(?!undb)w+)*
部分与,s?
模式不重叠。