【问题标题】:RegEx BackReference to Match Different Values正则表达式反向引用以匹配不同的值
【发布时间】:2018-11-25 07:11:31
【问题描述】:

我有一个正则表达式,用于匹配 (val1 operator val2) 形式的表达式

这个正则表达式看起来像:

(\(\s*([a-zA-Z]+[0-9]*|[0-9]+|\'.*\'|\[.*\])\s*(ni|in|\*|\/|\+|\-|==|!=|>|>=|<|<=)\s*([a-zA-Z]+[0-9]*|[0-9]+|\'.*\'|\[.*\])\s*\))

这实际上很好并且符合我想要的,如您所见here in this demo

但是:D(黄油来了)

我想优化正则表达式本身,使其更具可读性和“紧凑性”。我搜索了如何做到这一点,我发现了一种叫做反向引用的东西,你可以在其中命名你的捕获组,然后稍后引用它们:

(\(\s*(?P<Val>[a-zA-Z]+[0-9]*|[0-9]+|\'.*\'|\[.*\])\s*(ni|in|\*|\/|\+|\-|==|!=|>|>=|<|<=)\s*(\g{Val})\s*\))

我将捕获表达式左侧的组命名为Val,后来我将其引用为(\g{Val}),现在问题是这个表达式,如您所见here只有表达式左侧与右侧完全相同的情况!例如(a==a)(1==1)(a==b) 等表达式不匹配!

现在的问题是:有没有办法引用模式而不是匹配的值?!

【问题讨论】:

  • 在 PCRE 中,应该是 (?&amp;Val),而不是 \g{Val}。你的正则表达式引擎是什么?
  • 我正在使用 PHP 抱歉我忘了标记它

标签: php regex pcre


【解决方案1】:

注意\g{N} 等价于\1,即一个反向引用,它匹配对应的捕获组匹配的相同,而不是模式.不过这种语法更灵活一些,因为您可以通过在数字前使用- 来定义与当前组相对 的捕获组(即\g{-2}(\p{L})(\d)\g{-2} 将匹配@ 987654329@)。

PCRE 引擎允许subroutine calls 递归子模式。要重复第 1 组的模式,请使用 (?1)(?&amp;Val) 递归命名组 Val 的模式。

此外,您可以使用字符类来匹配单个字符,并考虑使用? 量词使正则表达式的某些部分成为可选:

(\(\s*(?P<Val>[a-zA-Z]+[0-9]*|[0-9]+|\'.*\'|\[.*\])\s*(ni|in|[*\/+-]|[=!><]=|[><])\s*((?&Val))\s*\))

regex demo

注意\'.*\'\[.*\] 可以匹配太多,考虑替换为\'[^\']*\'\[[^][]*\]

【讨论】:

  • 请注意,(?&amp;Val) 必须包装到单独的捕获组中才能捕获值,因此 ((?&amp;Val))
  • 感谢您的建议,我将更改数组和字符串匹配器:) +1
  • 顺便说一句,如果我想匹配像 ((a+1)==(b*5)) 这样的递归表达式怎么办 .. 在这种情况下,我的表达式将只匹配两个表达式 (a+1)(b*5) 我如何调整它以匹配整个表达式!?
  • 如果您应用递归,您将丢失其中的捕获。你真的想要吗?使用基本表达式将所有嵌套括号与/\((?&gt;[^()]++|(?R))*\)/ 匹配,然后用您的表达式解析每个括号。或者摆脱所有这些花哨的东西,使用/[a-zA-Z]+[0-9]*|[0-9]+|\'[^\']*\'|\[[^][]*\]/
  • 是的,我也出于好奇想知道这个:)
【解决方案2】:

您在哪种语言/应用程序中使用此正则表达式? 如果您可以选择将不同部分指定为命名变量,然后通过组合它们来构建最终的正则表达式。

val = "([a-zA-Z]+[0-9]*|[0-9]+|\'.*\'|\[.*\])"
op = "(ni|in|\*|\/|\+|\-|==|!=|>|>=|<|<=)"
exp = "(\(" .. val .. "\s*" .. op .. "\s*" .. val .. "\))"

【讨论】:

  • 我实际上正在这样做,但我出于好奇而问:D
猜你喜欢
  • 2020-12-03
  • 2020-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-06
相关资源
最近更新 更多