首页 > 解决方案 > 用 PCRE 提取“表达式语法”

问题描述

我们正在开发一个支持字符串外插表达式的项目。在后台,我们使用 Symfony 的表达式语言来提供上下文解析,但我们是从字符串中提取表达式的人。

我想先说一下,我不是正则表达式的专家。我的工作知识有限,因此以下正则表达式会显得笨拙和不雅:

/\${(.*?)}(?=[\s\w\-_\/\\:;,.?!()|"\]&]|$)/

理论是这样的:

  1. 表达式以 开头${。这是起始锚。
  2. 匹配那里的任何东西。
  3. 表达式以结束符结尾,}后跟行 end$或字符列表中的一项。

考虑一个看起来像这样的表达式:

他的名字是“ ${name}”,他是一个“ ${thing}”。

正则表达式将成功匹配表达式nameand thing,并将替换为来自值对象的值。

但是,如果我们考虑到用户也可以解析实际的表达式和值,那么:

${{"name": "Pack Rat", "mana_cost": "{1}{B}", "cmc": 2}}

意思是,将该表达式评估为 JSON 对象,正则表达式失败,因为它在}"part 中的序列处停止{1}{B},并且仅匹配{"name": "Pack Rat", "mana_cost": "{1}{B。在前瞻字符列表中删除"作为可能的停止点修复了 JSON,但是它无法从正则句子中提取两个表达式。

是否有可能避免这个表达式解析器过早停止?还是这超出了单个正则表达式的范围?

标签: phpregexpcre

解决方案


你可以使用

\$(\{(?:[^{}]+|(?1))+\})

并以此来进一步分析。在 regex101.com 上查看演示


详细地说,它是:

\$                       # "$" literally
(                        # opening bracket -> capture group 1
    \{                   # "{" literally
        (?:[^{}]+|(?1))+ # not { nor } or repeat the first group -> recursion
    \}                   # "}" 
)                        # end of group 1

推荐阅读