Pyparsing:使用nestedExp解析嵌套的类型化参数列表

2024-09-29 04:32:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个类型化的可选嵌套参数列表要解析。在

Input:
(int:1, float:3, list:(float:4, int:5))

Expected Dump:
[[['int', '1'], ['float', '3'], ['list', [['float', '4'], ['int', '5']]]]]

如果省略类型,则应根据以下值选择标准类型:

^{pr2}$

如您所料,我将使用parseAction中的类型在解析期间自动转换值。但这一步已经奏效了,所以我跳过这里。在

我对这个问题的处理方法是:

import pyparsing as pp

diCastTypes={
    "str": lambda value: value,
    "int": lambda value: int(value),
    "float": lambda value: float(value), 
    "tuple": lambda value: tuple(value),
    "list": lambda value: list(value),
    "set": lambda value: set(value),
    "dict": lambda value: dict(value),
}

bsQuoted = lambda expr : pp.Literal('\\').suppress() + expr

def parsingString (specialSigns = '', printables = pp.printables):
    seSpecialSigns = set(specialSigns).union(set('\\'))
    signs = ''.join(sorted(set(printables).difference(seSpecialSigns)))
    allowedLiterals = (
        pp.Literal(r"\t").setParseAction(lambda : "\t")      |
        pp.Literal(r"\ ").setParseAction(lambda : " ")       | 
        pp.Literal(r"\n").setParseAction(lambda : "\n")      | 
        pp.Word(signs)                                       |
        bsQuoted('"')                                        | 
        bsQuoted("'")
    )
    for special in seSpecialSigns:
        allowedLiterals = allowedLiterals | bsQuoted(special)           
    return pp.Combine(pp.OneOrMore(allowedLiterals))

value = parsingString('(),=:')
nestedValue = pp.Forward()
castPattern = pp.Optional(pp.oneOf(list(diCastTypes.keys())) + pp.Literal(":").suppress(), "str")("castType")
castPatternSeq = pp.Optional(pp.oneOf(list(diCastTypes.keys())) + pp.Literal(":").suppress(), "tuple")("castType")
parameterValue = pp.nestedExpr(content=(
    pp.Group( 
        (castPattern + value("rawValue")) | 
        (castPatternSeq + nestedValue)
    ) | 
    pp.Literal(',').suppress()
))
nestedValue <<= parameterValue

此实现几乎可以正常工作,但我的嵌套序列的默认值有一个严重问题:

parameterValue.parseString('(int:1, float:3, list:(float:4, int:5))').dump()
"[[['int', '1'], ['float', '3'], ['list', [['float', '4'], ['int', '5']]]]]"

parameterValue.parseString('(1, float:3, (4, int:5))').dump()
"[[['str', '1'], ['float', '3'], [['str', '4'], ['int', '5']]]]"

如您所见,序列的预期默认值tuple没有设置,结果列表的深度也不正确。我猜nestedExpr()在模式通过解析器(castPatternSeq + nestedValue)之前捕捉到(4, int:5)。这个问题对我来说很严重,因为我计划在nestedExpr模式中调用parserAction:

(castPattern + value("rawValue")).setParseAction(castParameter)) | 
(castPatternSeq + nestedValue).setParseAction(castParameter))

如果显式地给出了一个类型,那么这种方法很有效,但是如果不是这样,它当然会失败。在

有没有机会让nestedExpr少一点贪婪?在

更新1

嗨,伙计们。在昨天浪费了几乎一天的时间之后,今天早上我立即找到了解决上述问题的方法。在

我在实现中添加了一个delimitedList

value = parsingString('(),=:')
nestedValue = pp.Forward()
castPattern = pp.Optional(pp.oneOf(list(diCastTypes.keys())) + pp.Literal(":").suppress(), "str")("castType")
castPatternSeq = pp.Optional(pp.oneOf(list(diCastTypes.keys())) + pp.Literal(":").suppress(), "tuple")("castType")
parameterValue = pp.nestedExpr(content=pp.delimitedList(
    pp.Group( 
        (castPattern + value("rawValue")) | 
        (castPatternSeq + nestedValue)
    )
))
nestedValue <<= parameterValue

这很好,但不是很好,正如您在以下示例中看到的:

parameterValue.parseString('(int:1, (int:2, int:4))').dump()
"[[['int', '1'], ['tuple', [['int', '2'], ['int', '4']]]]]"

parameterValue.parseString('(int:1, ((int:2, int:4), (int:6, int9)) )').dump()
pyparsing.ParseException: Expected ")" (at char 6), (line:1, col:7)

parameterValue.parseString('(int:1, ((int:2, int:4) (int:6, int:9)) )').dump()
"[[['int', '1'], ['tuple', [[['int', '2'], ['int', '4']], [['int', '6'], ['int', '9']]]]]]"

parameterValue.parseString('(int:1, (tuple:(int:2, int:4) tuple:(int:6, int9)) )').dump()
"[[['int', '1'], ['tuple', [['tuple', [['int', '2'], ['int', '4']]], ['tuple', [['int', '6'], ['str', 'int9']]]]]]]"

示例2中的异常让我想到,nestedExpr和{}彼此之间的工作不太好,它们是从彼此身上捕捉到模式的。不管是什么原因,这似乎是一个全面的问题,因为如果我像示例3一样省略,,那么{}就没有什么可捕捉的了,整个模式都是匹配的。但并不像我预期的那样,因为默认类型又丢失了。只有没有,和显式类型,解析才能正常工作。在

有什么想法吗?在

更新2

问题是,声明

parameterValue.parseString('(int:1, ((int:2, int:4), (int:6, int9)) )').dump()

引发一个异常,可以通过稍微改变实现来解决(但这看起来更像是一种黑客行为,而不是真正的解决方案)。我刚刚添加了表达式| pp.Literal(",").suppress()

value = parsingString('(),=:')
nestedValue = pp.Forward()
castPattern = pp.Optional(pp.oneOf(list(diCastTypes.keys())) + pp.Literal(":").suppress(), "str")("castType")
castPatternSeq = pp.Optional(pp.oneOf(list(diCastTypes.keys())) + pp.Literal(":").suppress(), "tuple")("castType")
parameterValue = pp.nestedExpr(content=pp.delimitedList(
    pp.Group( 
        (castPattern + value("rawValue")) | 
        (castPatternSeq + nestedValue)
    )
) | pp.Literal(",").suppress())
nestedValue <<= parameterValue  

Tags: lambdavaluefloatlistppintstrtuple