在PyParsing中,如何将可选的解析结果转换为整数或如果不存在则转换为None

时间:2017-03-21 17:01:15

标签: python pyparsing

我正在使用内置PortRange方法编写课程parse

from pyparsing import Word, nums, Optional, Suppress

class PortRange(object):
    def __init__(self, start, end=None):
        self.start = start
        self.end = end if end is not None else self.start

    @staticmethod
    def parse(string):
        port = Word(nums)
        assignmentExpr = port.setResultsName('start') + Optional(Suppress("-") + port.setResultsName('end'))
        assignmentTokens = assignmentExpr.parseString(string)
        start = int(assignmentTokens.start)
        end = int(assignmentTokens.end)
        return PortRange(start=start, end=end)

PortRange对象具有startend属性,如果end在构造函数中被赋予None,则假定它是和开始一样。

PortRange也有一个字符串表示:如果startend相等,则它只是一个数字,而如果它们不同,则用连字符分隔(例如,5-10)。我尝试编写parse方法,使用pyparsing正确解析这两种情况。为此,我写了以下测试:

import pytest

'''Tests'''
def test_parse_full_port_range():               # This passes
    port_range = PortRange.parse("5-10")
    assert port_range.start == 5
    assert port_range.end == 10

def test_parse_port_range_with_start_only():    # This fails
    port_range = PortRange.parse("5")
    assert port_range.start == 5
    assert port_range.end == 5


if __name__ == "__main__":
    pytest.main([__file__])

问题是第二次测试失败了,因为你最终试图做

int('')

导致ValueError: invalid literal for int() with base 10: ''。在parse函数中,我希望end成为None,类似于使用符号组名称编写regular expression并使用{{}时的情况。 1}}。

我怎样才能做到这一点? (我尝试将groupdict()重新定义为port,但由于port = Word(nums).setParseAction(lambda x: int(x))中有0个参数,这会导致TypeError

2 个答案:

答案 0 :(得分:1)

assignementTokens似乎是一个字符串列表。而不是.start和.end atrributes,我使用[0]和[-1]作为开始和结束。在parse参数为“5”的情况下,start和end都设置为5(整数)。

start = int(assignmentTokens[0])
end = int(assignmentTokens[-1])

答案 1 :(得分:1)

根据Getting started with PyParsingParseResults.ParseResults类支持简单的基于列表的访问(在上面的答案中使用)以及对结果中命名字段的dict样式和对象属性样式访问。如果未解析可选字段,则dict样式访问似乎返回KeyError。所以我使用字典的get method来确保Noneend的默认值:

    start = int(assignmentTokens['start'])
    end = assignmentTokens.get('end', None)
    end = int(end) if end is not None else None

这也使得两个测试都通过了。