pypeg2 - 可以使用 peg 语法解析此表达式吗?
pypeg2 - can this expression be parsed using peg grammar?
我需要根据以下规则解析表达式:
- 表达式可以包含表示为
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 可以吗?
根据您在问题和评论中的规范,我认为您的代码很接近 - 但您不想要 csl
。我把我认为你想要的代码放在下面(它可能不是最优雅的实现,但我认为它是合理的)。您必须避免 BooleanLiteral
是 StringLiteral
的子集的潜在问题。这意味着你不能让 LineExpression
有
grammar = maybe_some([LineFilter,StringLiteral]), optional(BooleanLiteral)
我认为结果是根据您的规范具有正确类型的对象列表。我认为需要强调的关键一点是,您可以将替代项作为 python list
(即 [LineFilter,StringLiteral]
表示 LineFilter
或 StringLiteral
)。 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'>
我需要根据以下规则解析表达式:
- 表达式可以包含表示为
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 可以吗?
根据您在问题和评论中的规范,我认为您的代码很接近 - 但您不想要 csl
。我把我认为你想要的代码放在下面(它可能不是最优雅的实现,但我认为它是合理的)。您必须避免 BooleanLiteral
是 StringLiteral
的子集的潜在问题。这意味着你不能让 LineExpression
有
grammar = maybe_some([LineFilter,StringLiteral]), optional(BooleanLiteral)
我认为结果是根据您的规范具有正确类型的对象列表。我认为需要强调的关键一点是,您可以将替代项作为 python list
(即 [LineFilter,StringLiteral]
表示 LineFilter
或 StringLiteral
)。 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'>