pypeg2 - 可以使用 peg 语法解析这个表达式吗?

Posted

技术标签:

【中文标题】pypeg2 - 可以使用 peg 语法解析这个表达式吗?【英文标题】:pypeg2 - can this expression be parsed using peg grammar? 【发布时间】:2016-02-29 09:37:20 【问题描述】:

我需要根据以下规则解析表达式:

    表达式可以包含表示为name:value 的过滤器对象 表达式可以包含字符串表达式 表达式可以包含布尔值 OR,AND 里面的东西都可以引用

所以一个典型的表达式看起来像

filter1:45 hello world filter:5454

filter1:45 'hello world' filter:5454

hello world

'hello world' OR filter:43


这是我迄今为止尝试过的:

class BooleanLiteral(Keyword):
    grammar = Enum(K("OR"), K("AND"))

class LineFilter(Namespace):
    grammar = flag('inverted', "-"), name(), ":", attr('value', word)

class LineExpression(List):
    grammar = csl(LineFilter, separator=blank)

有了这个语法,我可以解析像这样的字符串

filter2:32 filter1:3243

据我了解,我可以为csl 函数提供对象列表,并且语法需要按该顺序排列。但是,如果我想解析像

这样的对象怎么办

filter34:43 hello filter32:3232

filter34:43 OR filter32:3232

我怎么能说一个表达式中有多种类型的对象(过滤器、表达式、布尔值)?用 peg 可以吗?

【问题讨论】:

这绝对可以做到——只需要澄清几件事。过滤器、布尔值和文字的顺序完全不重要吗?即您可以按任何顺序拥有任意数量的它们吗?其次-当您说可以引用任何内容时-这是否意味着可以引用过滤器或布尔值以及字符串文字?是正常的分隔符空格(好像是这样)。如果空格是分隔符,带引号的字符串是否算作一个记号,还是几个记号?例如hello world 是两个令牌(helloworld),还是一个?对于"hello world",你如何回答同样的问题? 您好,感谢您的评论,1) 唯一有意义的限制是布尔值不能相邻,但需要分隔 filter OR filterexpression OR expressionexpression OR filter。否则有任意数量的过滤器和表达式,并且没有指定顺序。 2) 可以引用字符串文字和布尔值,而不是过滤器 3) 空格是正常的分隔符。 4) 带引号的字符串 = 一个标记。所以hello worldhello world"hello world"hello world。我回答了你所有的问题吗? 这一切都说得通,并回答了问题——我会尽量看看。 哦——我又想到了一件事——你在使用 PyPEG 2.15 吗?我想是的。 @JRichardSnape 是的,它的版本:2.15.0 【参考方案1】:

根据您在问题和 cmets 中的规范,我认为您的代码很接近 - 但您不想要 csl。我把我认为你想要的代码放在下面(它可能不是最优雅的实现,但我认为它是合理的)。您必须避免BooleanLiteralStringLiteral 的子集的潜在问题。这意味着你不能让LineExpression 拥有

grammar = maybe_some([LineFilter,StringLiteral]), optional(BooleanLiteral)

我认为,根据您的规范,结果是具有正确类型的对象列表。我认为要强调的关键一点是,您可以将替代品作为 python list (即[LineFilter,StringLiteral] 表示LineFilterStringLiteral)。 PEG 解析器将按照它们发生的顺序尝试它们,即它会尝试匹配第一个,只有当它失败时才会尝试第二个等等。

from pypeg2 import *

class BooleanLiteral(Keyword):
    # Need to alter keyword regex to allow for quoted literal keywords
    K.regex=re.compile(r'"*\w+"*') 
    grammar = Enum(K('OR'), K('AND'),K(r'"OR"'), K(r'"AND"')) 

class LineFilter(Namespace):
    grammar = flag('inverted', "-"), name(), ":", attr('value', word)

class StringLiteral(str):
     quoted_string = re.compile(r'"[^"]*"')
     grammar = [word, quoted_string]

class LineExpression(List):
    grammar = maybe_some([(LineFilter,BooleanLiteral),
                          (StringLiteral,BooleanLiteral),
                          LineFilter,
                          StringLiteral])

test_string = ('filter34:43 "My oh my!!" Hello OR '
               'filter32:3232 "AND" "Goodbye cruel world"')

k = parse(test_string,LineExpression)

print('Input:')
print(test_string)
print('Parsed output:')
print('==============')
for component in k:
    print(component,type(component))

输出

Input:
filter34:43 "My oh my!!" Hello OR filter32:3232 "AND" "Goodbye cruel world"
Parsed output:
==============
LineFilter([], name=Symbol('filter34')) <class '__main__.LineFilter'>
"My oh my!!" <class '__main__.StringLiteral'>
Hello <class '__main__.StringLiteral'>
OR <class '__main__.BooleanLiteral'>
LineFilter([], name=Symbol('filter32')) <class '__main__.LineFilter'>
"AND" <class '__main__.BooleanLiteral'>
"Goodbye cruel world" <class '__main__.StringLiteral'>

【讨论】:

以上是关于pypeg2 - 可以使用 peg 语法解析这个表达式吗?的主要内容,如果未能解决你的问题,请参考以下文章

Python 之父的解析器系列之五:左递归 PEG 语法

Python PEG 中 bitwise_or 的目的是啥?

用于“表达式”的非左递归PEG语法

Python 之父的解析器系列之三:生成一个 PEG 解析器

什么是 Packrat 解析?

正确认高分子PEG:识MTA mPEG,Myristic-acid PEG,肉豆蔻酸 PEG,PEG改性肉豆蔻酸