在 PyParsing 中,如何将可选的解析结果转换为整数或 None(如果不存在)
In PyParsing, how to convert an optional parse result to an integer or None if not present
我正在编写一个 class 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
对象有start
和end
属性,如果end
在构造函数中作为None
给出,假定和开头一样。
PortRange
也有字符串表示:如果start
和end
相等,则只是一个数字,如果不同则用连字符分隔(例如,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 并使用 groupdict()
.
我怎样才能做到这一点? (我尝试将 port
重新定义为 port = Word(nums).setParseAction(lambda x: int(x))
,但这会导致 TypeError
,因为 lambda
中有 0 个参数。
assignementTokens 似乎是一个字符串列表。我没有使用 .start 和 .end 属性,而是使用 [0] 和 [-1] 作为开始和结束。在解析参数为“5”的情况下,开始和结束都设置为 5(整数)。
start = int(assignmentTokens[0])
end = int(assignmentTokens[-1])
根据Getting started with PyParsing, the ParseResults.ParseResults
class supports simple list-based access (used in the answer above) as well as dict-style and object attribute-style access to named fields within the results. It seems like the dict-style access returns a KeyError
if the optional field was not parsed. So I used the dictionary's get method确保None
是end
的默认值:
start = int(assignmentTokens['start'])
end = assignmentTokens.get('end', None)
end = int(end) if end is not None else None
这也使两个测试都通过了。
我正在编写一个 class 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
对象有start
和end
属性,如果end
在构造函数中作为None
给出,假定和开头一样。
PortRange
也有字符串表示:如果start
和end
相等,则只是一个数字,如果不同则用连字符分隔(例如,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 并使用 groupdict()
.
我怎样才能做到这一点? (我尝试将 port
重新定义为 port = Word(nums).setParseAction(lambda x: int(x))
,但这会导致 TypeError
,因为 lambda
中有 0 个参数。
assignementTokens 似乎是一个字符串列表。我没有使用 .start 和 .end 属性,而是使用 [0] 和 [-1] 作为开始和结束。在解析参数为“5”的情况下,开始和结束都设置为 5(整数)。
start = int(assignmentTokens[0])
end = int(assignmentTokens[-1])
根据Getting started with PyParsing, the ParseResults.ParseResults
class supports simple list-based access (used in the answer above) as well as dict-style and object attribute-style access to named fields within the results. It seems like the dict-style access returns a KeyError
if the optional field was not parsed. So I used the dictionary's get method确保None
是end
的默认值:
start = int(assignmentTokens['start'])
end = assignmentTokens.get('end', None)
end = int(end) if end is not None else None
这也使两个测试都通过了。