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

时间:2015-07-07 14:11:21

标签: python nested pyparsing

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

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

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

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

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

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

正如您所料,我将使用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']]]]"

如您所见,未设置序列的预期默认值元组,并且结果列表的深度不正确。我想nestedExpr()在通过解析器(4, int:5)之前捕获了模式(castPatternSeq + nestedValue)。这个问题对我来说很严重,因为我打算在 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中的例外让我想到,nestedExprdelimitedList彼此不能很好地工作,他们正在相互捕捉模式。无论原因是什么,这似乎都是问题所在,因为如果省略示例3中的,delimitedList没有什么可以捕捉到的,整个模式都匹配。但不像我预期的那样,因为默认类型再次丢失。只有没有,和显式类型,解析才能正常工作。

有什么想法吗?

更新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  

0 个答案:

没有答案