PyParsing 的 searchString 与 StringStart() 和 StringEnd()

PyParsing's searchString with StringStart() and StringEnd()

我正在尝试通过以下测试:

from pyparsing import Word, nums, StringStart, StringEnd
import pytest

def get_square_feet(string):
    area = Word(nums+",")("area").setParseAction(lambda s, l, t: [int(t[0].replace(',', ''))])
    expression = StringStart() + area + "sqft" + StringEnd()
    return expression.parseString(string).get("area")

def test_get_square_feet():
    assert get_square_feet("800 sqft") == 800
    assert get_square_feet("9,000 sqft") == 9000

def test_get_square_feet_with_prefix():
    assert get_square_feet("size: 12,000 sqft") is None

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

然而,第二个测试失败了,因为它导致 ParseError。相反,我想使用 searchString,但是如果我在 get_square_feet 函数中将 parseString 替换为 searchString 我也会收到错误消息,因为函数 returns None。有人可以指出这里有什么问题吗?

这是 get_square_feet 的一个实现,它使用正则表达式通过了测试:

def get_square_feet(string):
    match = re.match(r'^([\d,]+) sqft$', string)
    return int(match.groups()[0].replace(',', '')) if match else None

原则上,PyParsing 应该比正则表达式更容易使用,所以我仍然对使用 PyParsing 的解决方案感兴趣。

下面是使用pyparsing 捕获ParseException 的相应代码:

from pyparsing import Word, nums, StringStart, StringEnd, ParseException

def get_square_feet(string):
    area = Word(nums+",")("area").setParseAction(lambda s, l, t: [int(t[0].replace(',', ''))])
    expression = StringStart() + area + "sqft" + StringEnd()
    try:
        return expression.parseString(string).get("area")
    except ParseException:
        return None

这是一个使用 parsy 的解决方案,它在许多方面类似于 pyparsing,但具有更好的界面和实现 IMO。

from parsy import regex

def get_square_feet(s):
    area = regex(r'[0-9,]+').map(lambda s: int(s.replace(',', '')))
    return (area << string(" sqft") | regex('.*').result(None)).parse(s)

这里我们使用 | 组合器回退到接受任何内容的正则表达式,然后根据需要生成 None。您还可以通过捕获 ParseError 异常并在这种情况下返回 None 来实现它。