PHP、preg_match_all、使用 PREG_OFFSET_CAPTURE 的匹配组中的意外匹配项

PHP, preg_match_all, unexpected matches in matching groups using PREG_OFFSET_CAPTURE

我有以下正则表达式:

/(\bafter[\s_:.,()-]+|\bnach[\s_:.,()-]+|\bd'apres[\s_:.,()-]+|\bd´apres[\s_:.,()-]+|\bCircle of[\s_:.,()-]+)*(Pablo[\s_:.,()-]+Picasso|Picasso[\s_:.,()-]+Pablo)([\s_:.,()-]+Nachfolge\b|[\s_:.,()-]+Nachfolger\b|[\s_:.,()-]+Nachfolgerin\b|[\s_:.,()-]+Werkstatt\b|[\s_:.,()-]+Umkreis\b|[\s_:.,()-]+d'apres\b|[\s_:.,()-]+d´apres\b|[\s_:.,()-]+Circle of\b)*/uim

输入字符串:This is a test Pablo Picasso bla

我正在使用 preg_match_all($regex, $input, $matches, PREG_OFFSET_CAPTURE) 获取所有匹配项及其偏移量。

结果:

array(4) {
  [0] =>
  array(1) {
    [0] =>
    array(2) {
      [0] =>
      string(13) "Pablo Picasso"
      [1] =>
      int(15)
    }
  }
  [1] =>
  array(1) {
    [0] =>
    array(2) {
      [0] =>
      string(0) ""
      [1] =>
      int(-1)
    }
  }
  [2] =>
  array(1) {
    [0] =>
    array(2) {
      [0] =>
      string(13) "Pablo Picasso"
      [1] =>
      int(15)
    }
  }
  [3] =>
  array(1) {
    [0] =>
    string(0) "" // why is this type string and no array containing empty string + negative offset (-1) as values?
  }
}

为什么 array[3][0](第三个匹配组,第一个匹配项)是一个空字符串,而不是像 array[1][0] 第一个匹配组,第一个匹配项那样具有相同偏移量的数组 -1

array(2) {
  [0] =>
  string(0) ""
  [1] =>
  int(-1)
}

如果我使用以下输入字符串,则此位置有一个数组作为匹配结果:This is a test after Pablo Picasso (d'apres)(因为匹配(d'apres)。

参见示例:https://regex101.com/r/euKHUW/2

环境:

PHP 7.2.12 (cli) (built: Nov 24 2018 18:28:09) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.12, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans

如果没有找到第三个匹配组的匹配项,第一个匹配项,为什么没有包含作为第一个键的空字符串和作为第二个键的负偏移量 (-1) 的数组?

模式末尾的可选组,未显示。

您实际上可以使这些可选的重复组成为非捕获组,并用捕获组括起来以始终获取它们,请参阅 this regex demo。然后,您只需检查返回的组是否与空字符串匹配。

您还可以采取其他步骤来简化模式:

  • \bd'apres[\s_:.,()-]+|\bd´apres[\s_:.,()-]+可以写成\bd[´']apres[\s_:.,()-]+
  • \bafter[\s_:.,()-]+|\bnach[\s_:.,()-]+...可以写成\b(?:after|nach)[\s_:.,()-]+,使用内部非捕获组并且只有一次重复模式。

查看修改后的图案:

((?:\b(?:after|nach|d[´']apres|Circle of)[\s_:.,()-]+)*)(Pablo[\s_:.,()-]+Picasso|Picasso[\s_:.,()-]+Pablo)((?:[\s_:.,()-]+(?:(?:Nachfolge(?:r(?:in)?)?|Werkstatt|Umkreis|d['´]apres|Circle of)\b))*)

regex demo