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

时间:2015-11-26 10:25:01

标签: python regex parsing grammar peg

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

  1. 表达式可以包含表示为name:value
  2. 的过滤器对象
  3. 表达式可以包含字符串表达式
  4. 表达式可以包含布尔值OR,AND
  5. 内部的所有内容都可以引用
  6. 所以典型的表达式看起来像

    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

    OR

    filter34:43 OR filter32:3232

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

1 个答案:

答案 0 :(得分:6)

根据问题和评论中的规范,我认为您的代码很接近 - 但您不想要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'>