【问题标题】:competing regular expressions (race condition)竞争正则表达式(竞争条件)
【发布时间】:2022-01-23 02:46:15
【问题描述】:

我正在尝试使用 python PLY (lex/yacc) 来解析一种名为“GRBL”的语言。 GRBL 看起来像这样:

G00 X0.0 Y0.0 Z-1.0
G01 X1.0
..

“G”代码告诉机器“走”(或移动),而坐标则告诉机器在哪里。

LEX 要求我们为每个可能的“令牌”指定一个唯一的正则表达式。

所以在这种情况下,我需要一个明确定义“G00”的正则表达式和一个明确定义“G01”等的正则表达式。

显然,一个人的第一个想法是r'G00' 等。 但是 G 代码是不精确的。 G可以是大写或小写,可以有前导零等。

(g0、G00、g001 等)

所以对于 G00 来说可能很简单:

r'[Gg]{1}0*'

对于 G01,我们可以有

r'[Gg]{1}0*1'

但这不起作用。 G00 解析正确,但 G01 给出:

LexToken(G00,'G0',3,21)
Illegal character '1'

也就是说,lex 认为 G01 是 G0 令牌,不知道如何处理“1”。 这显然是某种贪婪匹配问题。

很遗憾,我不能使用“$”终止符来指定字符串必须以“1”“结束”

我意识到这对某些人来说可能看起来很简单,但我已经做了 3 个小时了,但无法让它发挥作用!有谁知道如何解决这个问题?

【问题讨论】:

  • 竞争条件是异步代码的计时问题(结果取决于两个任务运行的顺序)。这里没有什么异步的。
  • @rici 是的,但我不知道可能有“多少”前导零。而且我只在“Gg”代码上使用 {1},因为我想要 G|g(我本来可以这样做)
  • 我并不是说你没有问题,只是它的术语不是“竞争条件”。
  • 对使用{1} 的解释毫无意义。你可以写[Gg]0*。为什么你认为会有问题?

标签: python regex parsing race-condition ply


【解决方案1】:

注意:没有理由在正则表达式中写入{1}。这意味着前一个元素应该只重复一次,如果没有重复运算符,就会发生这种情况。所以它所做的只是混淆正则表达式(并减慢匹配速度)。

但这不是你的问题。您的问题可能是 Ply 应用正则表达式的顺序。 Ply 通过将所有模式连接成一组备选方案来创建一个庞大的 Python 正则表达式:

(pattern1)|(pattern2)|(pattern3)|...|(patternz)

插入模式的顺序很重要,因为 Python“正则”表达式使用有序的交替运算符(使它们在数学术语中实际上是不规则的,但这是一个附带问题)。所以一旦一些替代匹配,下面的甚至都没有尝试过。

Ply 手册定义了顺序:

  1. 函数定义的所有标记都按照它们在词法分析器文件中出现的顺序添加。
  2. 接下来添加由字符串定义的标记,方法是按照正则表达式长度递减的顺序对它们进行排序(首先添加较长的表达式)。

我猜您正在使用函数,因此模式在文件中按出现顺序排列,因为如果将它们定义为字符串,您的第二个模式(更长)将首先应用。但是如果没有看到您的实际文件,很难确定。

无论如何,Ply 词法分析器的传统智慧是使用尽可能少的模式,更喜欢将关键字映射到带有字典的标记。在 GRBL 的情况下,一种可能性可能是使用 [Gg][0-9]+(\.[0-9]÷)? 作为模式,然后在语义操作中提取索引。

【讨论】:

  • 这很有趣。有一种方法可以指定单个正则表达式模式,然后对每个标记进行后处理?您在某处有对此的参考吗?
  • 我会将您的答案标记为正确,因为简单地反转动态生成的令牌数组确实直接解决了我的问题,尽管不像我预期的那样。
  • @richard:请参阅 Ply 手册,其中他谈到了处理关键字标记
【解决方案2】:

您的模式 [Gg]{1}0* 是通用的,它匹配 G00 和 G01 https://regex101.com/r/gkz0Wb/1 在第二种情况下,您只剩下单个字符 1

您必须使该模式更具体,例如通过在结尾模式 [Gg]{1}0*\s 添加空格字符 https://regex101.com/r/dsSFaG/1

【讨论】:

  • LEX 占用空格。这是问题之一
猜你喜欢
  • 2018-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多