Regex 递归子模式不';我似乎不能轮流工作

Regex 递归子模式不';我似乎不能轮流工作,regex,pcre,Regex,Pcre,我想用逗号分隔的数字来匹配字符串。简而言之,我想在1-16范围内最多匹配8个数字。所以字符串1,2,3,4,5,6,7,8是可以的,而1,2,3,4,5,6,7,8,9不是,因为它有9个数字。而且16正常,但17不正常,因为17不在范围内 我试图使用这个正则表达式^((?:[1-9]| 1[0-6]),{0,7}([1-9]| 1[0-6])$ 而且效果很好。我使用交替匹配从1到16的数字,然后我使用0..7重复,在末尾加逗号,然后在结尾不加逗号。但是我不喜欢子模式的重复,所以我尝试了(?1)递

我想用逗号分隔的数字来匹配字符串。简而言之,我想在1-16范围内最多匹配8个数字。所以字符串
1,2,3,4,5,6,7,8
是可以的,而
1,2,3,4,5,6,7,8,9
不是,因为它有9个数字。而且
16
正常,但
17
不正常,因为17不在范围内

我试图使用这个正则表达式
^((?:[1-9]| 1[0-6]),{0,7}([1-9]| 1[0-6])$
而且效果很好。我使用交替匹配从1到16的数字,然后我使用0..7重复,在末尾加逗号,然后在结尾不加逗号。但是我不喜欢子模式的重复,所以我尝试了
(?1)
递归第一个捕获组。我的正则表达式看起来像
^(?([1-9]| 1[0-6]),{0,7}(?1)$
。但是,当最后一个数字有两个字母(10-16)时,这不会产生匹配。它确实匹配
1,1
,但不匹配
1,10
。我不明白为什么

我创造了一个问题的例子

在调试器中,我看到当模式递归时,引擎不会尝试组中的第二个替换。我希望它能起作用。问题出在哪里?

这是因为PCRE中的是原子

您拥有的正则表达式可以重新编写为
^(([1-9]|1[0-6]),{0,7}(>[1-9]|1[0-6])$
,请参阅
(?>…|…)
将不允许回溯到此组,因此如果第一个分支“获胜”(如您的示例中所示),则在下一个子模式失败时不会尝试后续分支(此处,
$
在匹配
1
后无法匹配字符串结尾-后面跟着
0

您可以交换备选方案。在这种情况下,时间越长越好:

^(?:(1[0-6]|[1-9]),){0,7}(?1)$

通常,最佳实践是组中的每个备选方案必须在字符串中的不同位置匹配。它们不应在相同的位置匹配


如果无法重写替换组,使每个替换项在字符串中的唯一位置匹配,则应在不使用正则表达式子例程的情况下重复该组。

可以使用PCRE2 version>=10.30。它使子例程类似于Perl(非原子)。您的正则表达式必须按预期工作。