如何使用 PLY 处理括号内 STRING 表达式之间的 OR 运算符

How to handle OR operator between STRING expressions inside parenthesis with PLY

我想解释这样的句子:

 "i + want + to + turn + ( on | off ) + the + lights"

得到像这样的句子:

  "i want to turn on the lights"

  "i want to turn off the lights"

我尝试定义一个词法分析器和一个解析器来帮助我处理这个问题,但是 我不知道如何处理括号之间的表达式 和“OR”运算符,给出类似有效值的一个或另一个表达式 竖线 (|) 字符。

语法规则“+”(PLUS)在这种情况下的 STRING 是一个连接操作。

def p_expression_plus(p):
     'expression : expression PLUS term'
     p[0] = p[1] + ' ' + p[3]

但我不知道如何定义 OR 操作,并像我上面定义的那样以单独的方式获得括号之间的两个字符串的加法。

任何想法将不胜感激。谢谢!

我不认为这真的是一个解析问题,因为表达式的解析很简单。虽然你没有展示你的尝试,但你展示的内容足以表明你知道如何去做。所以我假设你的问题是 "How do I evaluate an expression which could return multiple strings?"

简单的解决方案似乎是将表达式计算为可能的字符串列表。如果你有很多选择,那将导致一个非常大的数组,但它在其他方面是直截了当的。基本思想由这个简单的 class:

封装
class StrExpr(object):
  def __init__(self, str=None, *args):
    '''Make a StrExpr from a single string and/or one or more iterators'''        
    self.alts = [str] if str is not None else []
    for arg in args: self.alts.extend(arg)

  def __add__(self, other):
    '''Return a new StrExpr from this one concatenated with another one'''
    if not isinstance(other, StrExpr): return NotImplemented
    return StrExpr(None, (l + ' ' + r for l in self.alts for r in other.alts))

  def __or__(self, other):
    '''Return a new StrExpr containing alternatives from this
       one and another one.
    '''
    if not isinstance(other, StrExpr): return NotImplemented
    return StrExpr(None, self.alts, other.alts)

  def __str__(self):
    return str(self.alts)

  def __repr__(self):
    return "StrExpr"+str(self.alts)

快速测试:

>>> a = ( StrExpr("i") + StrExpr("want") + StrExpr("to") + StrExpr("turn")
...     + (StrExpr("on") | StrExpr("off")) + StrExpr("the") + StrExpr("lights")
...     + (StrExpr("now") | StrExpr("later") | StrExpr("tomorrow"))
...     )
>>> a
StrExpr['i want to turn on the lights now', 'i want to turn on the lights later', 'i want to turn on the lights tomorrow', 'i want to turn off the lights now', 'i want to turn off the lights later', 'i want to turn off the lights tomorrow']
>>> print('\n'.join(a.alts))
i want to turn on the lights now
i want to turn on the lights later
i want to turn on the lights tomorrow
i want to turn off the lights now
i want to turn off the lights later
i want to turn off the lights tomorrow

一个更 Pythonic 的解决方案是使 StrExpr 成为一个延迟生成其替代品的生成器。但是原理是差不多的。