Python:正则表达式解析文本以创建dict

时间:2016-10-26 11:04:52

标签: python regex

我遇到一个任务问题:

我有来自cisco hw的输出。

IP access list 100  
        10 permit igmp any any  
        20 deny any any  
IP access list 200  
        10 permit ip 192.168.1.1/32   
        20 permit ip 192.168.2.1/32 any  
        30 permit ip 192.168.3.3/32 any  
        40 deny any any

任务是制作一个dict,其中访问列表编号为密钥,访问列表规则编号为值。

acl_dict = {'100' : '10', '100' : '20','200': '10', '200': '20', '200': '30', '200': '40'}

我写了一个正则表达式:

rx = re.compile("""
                   list\s(.*)[\n\r]
                   \s{4}(\d{1,3}).+$
                 """,re.MULTILINE|re.VERBOSE)
         for match in rx.finditer(text):
             print (match.group(1))
             print (match.group(2))

但是只显示前两个字符串中的数字(100和10) 我需要以某种方式修改正则表达式以匹配所有数字以使所需的字典。 有人可以帮忙吗?

2 个答案:

答案 0 :(得分:2)

可以使用最新的 regex 模块通过单一方法完成此操作:

import regex

text = """
IP access list 100  
    10 permit igmp any any  
    20 deny any any  
IP access list 200  
    10 permit ip 192.168.1.1/32   
    20 permit ip 192.168.2.1/32 any  
    30 permit ip 192.168.3.3/32 any  
    40 deny any any
"""

acl_dict = {}
rx = regex.compile("list\s(.+)[\n\r](\s{4}(\d{1,3}).+[\n\r])*", regex.MULTILINE|regex.VERBOSE)
for match in rx.finditer(text):
    acl_dict[match.group(1)] = match.captures(3)

print(acl_dict)

输出:

$ python3 match.py 
{'200  ': ['10', '20', '30', '40'], '100  ': ['10', '20']}

答案 1 :(得分:1)

您可以先提取完整的块,然后从内部部分获取前导数字(可以捕获)。

使用

r'(?sm)IP access list\s+(\d+)(.*?)(?=^IP access list|\Z)'

请参阅regex demo

<强>详情:

  • (?sm) - 启用DOTALL和MULTILINE模式
  • IP access list - 文字字符串IP access list(如果始终位于第一行,则可以加^
  • \s+ - 一个或多个空格
  • (\d+) - 第1组:一个或多个数字
  • (.*?) - 第2组:任何0 +字符尽可能少到第一个......
  • (?=^IP access list|\Z) - IP access list位于字符串的开头或结尾(\Z)。

Python sample code

import re
input_str = "IP access list 100  \n        10 permit igmp any any  \n        20 deny any any  \nIP access list 200  \n        10 permit ip 192.168.1.1/32   \n        20 permit ip 192.168.2.1/32 any  \n        30 permit ip 192.168.3.3/32 any  \n        40 deny any any"
results = {}
for match in re.finditer(r"(?sm)IP access list\s+(\d+)(.*?)(?=^IP access list|\Z)", input_str):
    fields = re.findall(r"(?m)^\s*(\d+)", match.group(2))
    results[match.group(1)] = fields
print(results) # => {'200': ['10', '20', '30', '40'], '100': ['10', '20']}