使用pyparsing进行对端口表述的语法解析
下面的代码表示的是对各种形式表达的端口进行转换到端口对或端口的形式。
import unittest
from pyparsing import alphas, nums, alphanums, Suppress, Word, CaselessLiteral, \
OneOrMore, ZeroOrMore, oneOf, Group, Optional, White, \
stringEnd, ParseException, stringStart, common
text = """123
1 - 555
1-66
1,55
1|55
1、55
1~55
1-88
2or99
11或899
1024, 1025-9999,36525或99999
1024, 1025-9999, 36525"""
def validate_integer_range(a, b):
"""限制范围"""
def _warp(tokens):
if a <= tokens.port <= b:
pass
else:
raise ParseException(f'invalid range: {a}-{b}, found:{tokens.port}')
return _warp
port = Word(nums, max=5, min=1).setResultsName('port')
port.setParseAction(common.convert_to_integer, validate_integer_range(1, 65535))
or_sp = Suppress(oneOf(', | / \\ 、 或'))
range_sp = Suppress(oneOf('- ~ —— -'))
range_port = Group(port + range_sp + port).setResultsName('port_range')
port_present = range_port | port
dsl = ZeroOrMore(port_present + or_sp) + port_present + Optional(or_sp) + stringEnd
class PyDSLTestCase(unittest.TestCase):
"""
https://zhuanlan.zhihu.com/p/259638397
https://pyparsing-docs.readthedocs.io/en/latest/HowToUsePyparsing.html#helper-methods
"""
def test_simple1(self):
for line in text.splitlines():
p = dsl.parseString(line)
# print(p.dump())
print(p)
def test_result_name(self):
s = '1,2,3/ 455-6778'
p = dsl.parseString(s)
print(p)
if __name__ == '__main__':
unittest.main()