5

我正在构建一个语法解析器来对使用点符号标识的对象执行简单的操作,如下所示:

DISABLE ALL;
ENABLE A.1 B.1.1 C

但在DISABLE ALL关键字ALL中匹配为 3Regex(r'[a-zA-Z]') => 'A', 'L', 'L'我用来匹配参数。

如何使用正则表达式制作 Word?AFAIK 我无法A.1.1使用 Word

请看下面的例子

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)
4

1 回答 1

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

您的命令的格式设置方式,您必须让解析器首先查看是否所有正在切换,然后再查找各个区域等。如果您需要支持可能显示为“启用 A.1 ALL”的内容,请使用否定前瞻为itemitem = ~all_ + (area ^ etc...)。(另请注意,我只替换item + pp.ZeroOrMore(item)pp.OneOrMore(item).)

于 2011-06-09T12:34:45.437 回答