【问题标题】:PHP, preg_match_all, unexpected matches in matching groups using PREG_OFFSET_CAPTUREPHP,preg_match_all,使用 PREG_OFFSET_CAPTURE 匹配组中的意外匹配
【发布时间】:2018-11-30 11:39:52
【问题描述】:

我有以下正则表达式:

/(\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](第三个匹配组,第一个匹配)是一个空字符串,而不是一个与-1 一样具有偏移量的数组,就像array[1][0] 第一个匹配组,第一个匹配?

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) 的数组,第一个匹配?

【问题讨论】:

  • 它是模式末尾的可选组,未显示。您实际上可以使这些可选的重复组不被捕获并用捕获组包围以始终获取它们,请参阅regex101.com/r/euKHUW/3
  • 太聪明了!现在我必须记住,我不能将-1 视为“未找到”,因为第一个和第三个匹配组也匹配“空”:只需检查返回的匹配是否为空字符串。谢谢!

标签: php regex preg-match-all


【解决方案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

【讨论】:

  • 你的回答很棒!我修改了我的正则表达式 - 现在它更干净了。但是,我不能使用您优化单词本身的部分(?:Nachfolge(?:r(?:in)?)?,因为这些单词来自数据库(用户可以指定它们,所以我需要按原样处理它们)。但是多亏了你,我学会了如何使用?: :)
猜你喜欢
  • 1970-01-01
  • 2011-08-07
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2011-10-01
  • 2013-05-01
  • 2014-04-08
  • 1970-01-01
相关资源
最近更新 更多