PHP PCRE - 正则表达式升级现在失败(灾难性回溯)+ 优化

PHP PCRE - Regex upgraded now failing (Catastrophic backtracking) + optimization

我第一次发布这个问题:

Wiktor Stribiżew 完美地回答了这个问题。现在,我想升级我的 Regex 表达式,以便我的参数支持 JSON 对象(或几乎,因为不支持孤独的 '{' 和 '[')。

我有两种表达方式:一种是成对的标签,一种是孤独的标签。我首先使用配对的,当所有替换完成后,我执行孤独的。修改后的孤独者在 regex101.com (https://www.regex101.com/r/HIEQZk/9), but the paired one tells me "castatrophic backtracking" (https://www.regex101.com/r/HIEQZk/8) 上运行良好,即使在 PHP 中不会崩溃。

谁能帮我 optimize/fix 这个相当庞大的正则表达式。 虽然转义看起来没什么用,但因为 begin/end 标记和拆分器可以自定义,所以不得不转义。 (配对的那个没有被转义,因为它不是 PHP 生成的那个,而是 Wiktor Stribiżew 用我做的修改制作的那个。)

我认为应该是 optimized/fixed 的唯一部分是我刚刚修改以支持 JSON 对象的 "parameters" 组。 (这些的测试可以在同一个regex101的早期版本中看到url。这里的是真正的HTML来解析。)

孤独的表情

~
 \{\{ #Instruction start

   ([^\^\{\}]+) # (Group 1) Instruction name OR variable to reach if nothing else after then
   (?:
     \^
     (?:([^\^\{\}]*)\^)? #(Group 2) Specific delimiter
     ([^\{\}]*{(?:[^{}\[\]]+|(?3))+}[^\{\}]*|[^\{\}]*\[(?:[^{}\[\]]+|(?3))+\][^\{\}]*|[^\{\}]+) # (Group 3) Parameters
   )?

 \}\} #Instruction end
~xg

配对表达式

~{{             # Opening tag start
  (\w+)         # (Group 1) Tag name
  (?:           # Not captured group for optional parameters
   (?:          # Not captured group for optional delimiter
    \^          # Aux delimiter
    ([^^\{\}]?) # (Group 2) Specific delimiter
   )?
   \^           # Aux delimiter
   ([^\{\}]*{(?:[^{}\[\]]+|(?3))+}[^\{\}]*|[^\{\}]*\[(?:[^{}\[\]]+|(?3))+\][^\{\}]*|[^\{\}]+)   # (Group 3) Parameters
  )?
 }}             # Opening tag end
  (             # (Group 4)
   (?>          
     (?R)       # Repeat the whole pattern
     |          # or match all that is not the opening/closing tag
     [^{]*(?:\{(?!{/?[^\{\}]*}})[^{]*)*
   )*           # Zero or more times
  )
 {{/}}        # Closing tag
~ix

在观看 regex101 中的 stepscounter/debugger 时,尝试将 (?: 非捕获组 替换为 (?> atomic groups to prevent/reduce backtracking wherever possible. Those are non capturing as well. And/or experiment with possessive quantifiers .

任何你不希望引擎返回并尝试其他不同方式的地方。

This is your updated demo 我刚刚将第一个 (?: 更改为 (?>