【问题标题】:regex, problem with backreference in pattern with preg_match_all正则表达式,preg_match_all 模式中的反向引用问题
【发布时间】:2011-08-28 08:53:06
【问题描述】:

我想知道这里的反向引用有什么问题:

preg_match_all('/__\((\'|")([^\1]+)\1/', "__('match this') . 'not this'", $matches);

它应该匹配 __('') 之间的字符串,但实际上它返回:

match this') . 'not this

有什么想法吗?

【问题讨论】:

  • 后向引用真的在 char 类中有效吗?
  • 对不起,有一个丢失\我已经更正了面糊
  • 继续下一个解决方案。

标签: php regex preg-match-all backreference


【解决方案1】:

您不能在字符类中使用反向引用,因为字符类只匹配一个字符,而反向引用可能匹配任意数量的字符,或者不匹配。

你想要做的事情需要一个否定的前瞻,而不是一个否定的字符类:

preg_match_all('/__\(([\'"])(?:(?!\1).)+\1\)/',
    "__('match this') . 'not this'", $matches);

我还将您的替换 - \'|" - 更改为字符类 - [\'"] - 因为它更有效,并且我转义了外括号以使其与文字括号匹配。


编辑:我想我需要扩展“更有效”的评论。我拿了exampleFriedl 用来证明这一点,并在RegexBuddy 中对其进行了测试。

应用于目标文本abababdedfg
^[a-g]+$ 在三个步骤后报告成功,而
^(?:a|b|c|d|e|f|g)+$ 需要 55 个步骤。

这是一个成功的比赛。当我在abababdedfz 上尝试时,
^[a-g]+$ 在 21 步后报告失败;
^(?:a|b|c|d|e|f|g)+$ 需要 99 步。

在这种特殊情况下,对性能的影响是如此微不足道,甚至不值得一提。我只是说,每当您发现自己在匹配相同事物的角色类别和替代品之间进行选择时,您几乎总是应该选择角色类别。只是一个经验法则。

【讨论】:

  • “更多”,真的吗?还有多少?
  • 是的,交替非常缓慢,应该避免的瘟疫。然而,断言甚至更慢。
  • @sln:这取决于断言的编写方式和使用方式(就像正则表达式本身一样)。无论如何,在大多数情况下,它们提供的灵活性非常值得对性能造成影响。但是,当您可以使用 [abc] 时,没有任何借口可以使用 (a|b|c) 之类的东西。
【解决方案2】:

我很惊讶它没有给你一个不平衡括号错误消息。

 /
   __
   (
       (\'|")
       ([^\1]+)
       \1
 /

这个[^\1]不会把捕获缓冲区1的内容放到一个字符中
班级。它与所有非“1”的字符相同。

试试这个:

/__\(('|").*?\1\).*/

您可以添加一个内部捕获括号来捕获引号之间的内容:
/__\(('|")(.*?)\1\).*/

编辑:如果不允许使用内分隔符,请使用 Qtax 正则表达式。
因为,('|").*?\1 即使不是贪婪的,仍然会匹配到尾随的锚点。在这种情况下__('all'this'will"match'),最好使用('[^']*'|"[^"]*) 作为

【讨论】:

  • 从技术上讲,我认为\1 将在字符类中被解释为八进制值为 1 的字符,但要点本质上是相同的(即[^\1] 没有做 OP认为是)。 Example.
【解决方案3】:

你可以使用类似的东西: /__\(("[^"]+"|'[^']+')\)/

【讨论】:

  • 如果不允许内分隔符,这将是首选方法。
  • 请注意,这种方法的缺点是如果不包含分隔符就无法捕获内部数据。
  • @sln:当然可以捕获它;只需为每个子模式使用不同的组:~__\(("(?<DQ>[^"']+)"|'(?<SQ>[^"']+)')\)~
  • @sln @Alan,或者如果你的风格支持,你可以使用(?|...)。例如:/__\((?|"([^"]+)"|'([^']+)')\)/。艾伦,我不会使用[^"'],不同引用字符的全部意义在于您可以在另一个中使用一个。 ;)
  • @Alan - 我应该说,如果没有独立捕获缓冲区的后处理逻辑来确定捕获哪个缓冲区,内部捕获就没有干净的方法。
【解决方案4】:

让你的正则表达式不贪婪:

preg_match_all('/__((\'|")([^\1]+)\1/U', "__('match this') . 'not this'", $matches)

【讨论】:

  • 不要在 char 类中使用反向引用。
  • 如果要匹配的字符串包含转义引号,你会怎么做?像这样: __('match that\'s') 。 “不是这个”:|
  • [^\1] 匹配除八进制值1 之外的任何字符@
猜你喜欢
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多