由于重复捕获组而不是捕获重复组而导致正则表达式不匹配


regex not matching due to repeated capturing group rather than capturing a repeated group

我有以下regexp:

/(?:['['{]*)(?:([A-G'-][^A-G']'}]*)+)(?:[']'}]*)/

与以下表达式:

{A''BsCb}

我期待3个匹配的结果

A''
Bs
Cb

但是在https://regex101.com/上测试只给我最后一次匹配Cb,并告诉我重复捕获组只捕获最后一次迭代,在重复组周围放置捕获组。

我想那就是我所做的!我以为我已经理解了这里所描述的问题http://www.regular-expressions.info/captureall.html因此,我的+外面有括号,里面有捕获组。

但是要么太迟了,要么我需要一个人的头不会在提到regexp时崩溃,告诉我我错在哪里。

您可以在项目0处使用preg_match_all的模式获得它:

~
(?:
    'G (?!'A) # contiguous to previous match, but not at the start of the string
  |
    { (?=[^}]* }) # start with { and check if a closing bracket follows 
  |
    '[ (?=[^]]* ]) # the same for square bracket
)
'K # start the match result here
[A-G] [^]A-G}]* 
~xS
演示

您正在尝试匹配重复的捕获组并获得捕获。这是不可能的PHP PCRE regex。

您可以做的是确保您提取所有{...}/[...]子字符串,从括号中修剪它们并使用简单的[A-G-][^A-G]* regex,或添加'G操作符,使您的regex不可维护,但工作为原始的。

解1为

/(?:[[{]*|(?!'A)'G)'K[A-G-][^A-G']}]*/

参见regex演示。注意:这个正则表达式不检查关闭的]},但它可以添加一个正向前看。

  • (?:[[{]*|(?!'A)'G) -匹配[{,零个或多个出现,或前一次成功匹配的结束位置
  • 'K -省略目前匹配的文本
  • [A-G-] - AG的字母和-
  • [^A-G']}]* -除AG以及]}以外的零个或多个字符。

参见PHP演示。

解2为

$re = '/(?|{([^}]*)}|'[([^]]*)])/'; 
$str = "{A''BsCb}"; 
$res = array();
preg_match_all($re, $str, $m);
foreach ($m[1] as $match) {
    preg_match_all('~[A-G-][^A-G]*~', $match, $tmp);
    $res = array_merge($tmp, $res);
}
print_r($res);

查看PHP演示

(?|{([^}]*)}|'[([^]]*)])正则表达式只匹配字符串,如{...}[...](但不是{...][...}),并捕获括号之间的内容到组1(因为分支重置组(?|...)重置每个分支中的组id)。然后,我们所需要的就是用更连贯的'~[A-G-][^A-G]*~'正则表达式抓取我们需要的内容。

你已经想明白了。关于@sln的评论,在PHP的正则表达式风格的PCRE中重复一个组时,没有办法在一个或不同的捕获组中收集每个单个匹配。在本例中,只捕获最后一个匹配项。

但是,如果断言在字符串的开始和结束处应该有大括号并不重要,并且您只需要这些值,则需要做的工作较少:

$array = array_filter(preg_split("~(?=[A-G])~", trim("{A''BsCb}", '[{}]')));

正则表达式:

(?=[A-G]) # Positive lookahead to find next character be one from character class

这个正则表达式将匹配所有相似的位置,以在split时输出正确的数据:

array(3) {
  [1]=>
  string(3) "A''"
  [2]=>
  string(2) "Bs"
  [3]=>
  string(2) "Cb"
}

现场演示