我正在构建一个语法分析器,对使用点分表示法标识的对象执行简单操作,如下所示:
DISABLE ALL;
ENABLE A.1 B.1.1 C
但在DISABLE ALL
中,关键字ALL
被匹配为3 Regex(r'[a-zA-Z]') => 'A', 'L', 'L'
我用来匹配参数。
如何使用正则表达式创建Word? AFAIK我无法使用Word
获取A.1.1
请参阅下面的示例
import pyparsing as pp
def toggle_item_action(s, loc, tokens):
'enable / disable a sequence of items'
action = True if tokens[0].lower() == "enable" else False
for token in tokens[1:]:
print "it[%s].active = %s" % (token, action)
def toggle_all_items_action(s, loc, tokens):
'enable / disable ALL items'
action = True if tokens[0].lower() == "enable" else False
print "it.enable_all(%s)" % action
expr_separator = pp.Suppress(';')
#match A
area = pp.Regex(r'[a-zA-Z]')
#match A.1
category = pp.Regex(r'[a-zA-Z]\.\d{1,2}')
#match A.1.1
criteria = pp.Regex(r'[a-zA-Z]\.\d{1,2}\.\d{1,2}')
#match any of the above
item = area ^ category ^ criteria
#keyword to perform action on ALL items
all_ = pp.CaselessLiteral("all")
#actions
enable = pp.CaselessKeyword('enable')
disable = pp.CaselessKeyword('disable')
toggle = enable | disable
#toggle item expression
toggle_item = (toggle + item + pp.ZeroOrMore(item)
).setParseAction(toggle_item_action)
#toggle ALL items expression
toggle_all_items = (toggle + all_).setParseAction(toggle_all_items_action)
#swapping order to `toggle_all_items ^ toggle_item` works
#but seems to weak to me and error prone for future maintenance
expr = toggle_item ^ toggle_all_items
#expr = toggle_all_items ^ toggle_item
more = expr + pp.ZeroOrMore(expr_separator + expr)
more.parseString("""
ENABLE A.1 B.1.1;
DISABLE ALL
""", parseAll=True)
答案 0 :(得分:4)
这是问题吗?
#match any of the above
item = area ^ category ^ criteria
#keyword to perform action on ALL items
all_ = pp.CaselessLiteral("all")
应该是:
#keyword to perform action on ALL items
all_ = pp.CaselessLiteral("all")
#match any of the above
item = area ^ category ^ criteria ^ all_
编辑 - 如果你有兴趣......
你的正则表达式非常相似,我想我会看到将它们合二为一的样子。这是一个使用单个正则表达式解析三个虚线符号的片段,然后使用解析操作来确定您获得的类型:
import pyparsing as pp
dotted_notation = pp.Regex(r'[a-zA-Z](\.\d{1,2}(\.\d{1,2})?)?')
def name_notation_type(tokens):
name = {
0 : "area",
1 : "category",
2 : "criteria"}[tokens[0].count('.')]
# assign results name to results -
tokens[name] = tokens[0]
dotted_notation.setParseAction(name_notation_type)
# test each individually
tests = "A A.1 A.2.2".split()
for t in tests:
print t
val = dotted_notation.parseString(t)
print val.dump()
print val[0], 'is a', val.getName()
print
# test all at once
tests = "A A.1 A.2.2"
val = pp.OneOrMore(dotted_notation).parseString(tests)
print val.dump()
打印:
A
['A']
- area: A
A is a area
A.1
['A.1']
- category: A.1
A.1 is a category
A.2.2
['A.2.2']
- criteria: A.2.2
A.2.2 is a criteria
['A', 'A.1', 'A.2.2']
- area: A
- category: A.1
- criteria: A.2.2
EDIT2 - 我看到原来的问题......
搞乱你的是pyparsing隐含的空白跳过。 Pyparsing将跳过定义的标记之间的空白,但反之则不然 - pyparsing不需要单独的解析器表达式之间的空格。所以在你的all_-less版本中,“ALL”看起来像3个区域,“A”,“L”和“L”。这不仅适用于Regex,而且适用于任何pyparsing类。查看pyparsing WordEnd类是否可能有助于强制执行此操作。
EDIT3 - 那么也许是这样......
toggle_item = (toggle + pp.OneOrMore(item)).setParseAction(toggle_item_action)
toggle_all = (toggle + all_).setParseAction(toggle_all_action)
toggle_directive = toggle_all | toggle_item
您的命令的格式化方式,您必须首先查看解析器是否在查找单个区域之前切换ALL等。如果您需要支持可能读取“ENABLE A.1 ALL”的内容,请使用item
:item = ~all_ + (area ^ etc...)
的负面预测。
(另请注意,我将item + pp.ZeroOrMore(item)
替换为pp.OneOrMore(item)
。)