pyparsing正则表达式作为单词

5

我正在构建一个语法解析器,用于对使用点符号表示法标识的对象执行简单操作,类似于这样:

DISABLE ALL;
ENABLE A.1 B.1.1 C

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

如何使用正则表达式生成单词?据我所知,我无法使用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)

1
其他的评论/回答去哪了?我认为它们对讨论很有用。 - PaulMcG
1
@Paul:Meta 上有一场讨论,抱怨高声望用户删除他们的糟糕答案以避免被踩的情况... ^^ - neurino
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

编辑2 - 我看到了原来的问题...

你困扰的是pyparsing的隐式空格跳过。 Pyparsing将跳过定义的标记之间的空格,但反之则不成立--pyparsing不需要在分开的解析器表达式之间有空格。因此,在没有“ALL”的情况下,"ALL"看起来像3个区域,“A”、“L”和“L”。这不仅适用于正则表达式,而且适用于几乎所有的pyparsing类。请看看pyparsing WordEnd类是否有助于强制执行它。

编辑3 - 然后可能是这样的...

toggle_item = (toggle + pp.OneOrMore(item)).setParseAction(toggle_item_action)
toggle_all = (toggle + all_).setParseAction(toggle_all_action)

toggle_directive = toggle_all | toggle_item

在命令格式化方面,您需要先让解析器查看是否正在切换所有内容,然后再查找各个区域等。如果您需要支持可能会读取"ENABLE A.1 ALL"的内容,则可以使用否定的前瞻方式来处理itemitem = ~all_ + (area ^ etc...)。(还请注意,我用pp.OneOrMore(item)替换了item + pp.ZeroOrMore(item)。)


首先感谢Paul提供的优秀pyparsing库,我需要将事物分开处理,因为某些操作允许在“criterion”上执行,但不允许在“area”或“category”上执行等等,所以我想要区分它们。由于“all_”与项不能使用“^”,因为它有完全不同的解析动作。如果你运行我上面的代码,你会得到错误的结果,但是如果你取消注释第42行,你就可以看到正确的结果(因为“ALL”匹配在“A”、“L”、“L”之前)。这是实现这个目标的唯一方法吗? - neurino
非常感谢,我现在对操作数顺序有了更深的理解(我一直困扰于逻辑“或”行为),也了解到了直到现在被忽略的“-”操作数。 - neurino
额...我被卡住了,不是粘住了:D - neurino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接