网络工程师Python正则表达式(re实验5,Finditer函数,列表推导式)

网络工程师Python正则表达式(re实验5,Finditer函数,列表推导式)

哈喽,大家好,我又来了。我们继续推进,这篇来一起学习finditer函数。这个函数非常适合用来解析行列报文回显,如“display interface interface brief”、“display ip interface brief”之类的。此外,本文后面还会体验一下列表推导式的魅力。话不多说,我们直接开始吧。

本文部分参考知乎专栏 @弈心网路行者》实验思想,推荐移步阅读。

本文部分参考书籍《Python for network engineers》,纯英文,推荐移步阅读。

本专栏简介及目录入口,如果您不知道从何读起,建议从这篇《目录》开始,连接如下:

Finditer函数概述

Finditer函数会根据正则规则,匹配后返回一个有match对象组成的可迭代对象(iter)。啥是可迭代对象呢?我自己的理解是你可以从某范围内,一个一个地把里面的东西给喊出来,这个范围就是一个可迭代对象。比如你钱包里有一大叠钞票,你可以把钞票一张一张的数出来,这钱包就是一个可迭代对象啦。这个比方可能不是很严谨,anyway,辅助理解咯。

另外值得提一下,根据该函数的使用说明,无论是否有匹配到,都会返回一个迭代器,而非None之类的。怎么查手册?如下。

>>> help(re.finditer)
Help on function finditer in module re:

finditer(pattern, string, flags=0)
    Return an iterator over all non-overlapping matches in the
    string.  For each match, the iterator returns a Match object.
    
    Empty matches are included in the result.

翻译一下么?来哩。

>>> help(re.finditer)
re模块中finditer函数的帮助

finditer(pattern, string, flags=0)
    函数返回一个迭代器这迭代器内容为字符串经正则规则处理命中的全部匹配项匹配项与匹配项是不能重叠的
    每个匹配项都是一个Match对象
    
    如全部没匹配中也是会返回迭代器。(只不过这个迭代器为空而已。)

一般我对一个没怎么用过或忘了怎么用的函数,我就在IDLE这么敲,于是快速看看怎么用或者是啥个意思。

如果这里您有点理解不了,没关系的,咱们跟着实验敲敲敲就知道了。

实验过程

第 1 步,解析display ip interface brief回显(常规方式)

建立一个文件夹。

output_from_cli为文本文件,内容如下:

*down: administratively down
^down: standby
(l): loopback
(s): spoofing
The number of interface that is UP in Physical is 3
The number of interface that is DOWN in Physical is 6
The number of interface that is UP in Protocol is 3
The number of interface that is DOWN in Protocol is 6

Interface                         IP Address/Mask      Physical   Protocol  
LoopBack0                         11.11.11.11/32       up         up(s)     
MEth0/0/1                         unassigned           down       down      
NULL0                             unassigned           up         up(s)     
Vlanif1                           192.168.11.11/24     up         up        
Vlanif10                          10.18.123.5/25       down       down      
Vlanif12                          12.1.1.3/29          *down      down      
Vlanif34                          34.1.1.5/24          down       down      
Vlanif172                         172.18.123.5/26      *down      down      
Vlanif192                         192.168.123.5/27     *down      down   

Python脚本文件,内容如下:

import re

with open('output_from_cli') as output:
    # 整个文本读进来
    output_text = output.read()

# 如必要可看一下读取的内容,格式是str
#print(output_text)

result = re.finditer(r'(\S+) +'
                     r'([\d./]+) +'
                     r'(up|down|\*down) +'
                     r'(up|down)',
                     output_text)

#如果写成一行可以这么写,上面分行的写法是为了更简洁好看一点而已,实际是等效的。
#result = re.finditer(r'(\S+) +([\d./]+) +(up|down|\*down) +(up|down)',output_text)

print(result)
print(type(result))

for match in result:
    print(match)

代码和正则表达式的意思我就不讲了,前面的文章已经反复提及了。跑一下Python脚本,截图如下。

结合groups()等知识,我们就可以对子组进行捕获提取了。大家调整下尝试。

第 2 步,解析display ip interface brief回显(列表推导式)

怎么把代码写得又短又好看,让别人觉得有点高大上的感觉呢?哈哈哈,来……

import re
from pprint import pprint

with open('output_from_cli') as output:
    regex = r'(\S+) +([\d./]+) +(up|down|\*down) +(up|down)'
    result = [match.groups() for match in re.finditer(regex, output.read())]

pprint(result)

这个我们用到了列表推导式,会稍微高阶一点,如果基础稍微熟悉了以后可以尝试写点这样的,简洁效率也高。但是如果基础不是很扎实的,就容易绕着绕着给绕晕了,自行评估哈。

result = [match.groups() for match in re.finditer(regex, output.read())] 

这句话解释一下

1、re.finditer(regex, output.read()),这里返回了迭代器(上一步的内容);

2、for match in ……,变量match在迭代其中挨个迭代,借助了for循环;

3、每次迭代,变量match又调用了方法groups();

4、处理后结果被中括号[]括起来,形成列表赋值给变量result。

短小精悍的一句代码,里面包含了很多知识点,需要反复品味。来,跑一下看看。

其实对于咱普通网工来说,啧啧啧~,也不用太炫技太追求效率啦。能实现目标才是关键,老老实实的写,多几行代码又何妨呢?

第 3 步,温故知新日志例子(用finditer函数)

早前,我们用search和match函数做了日志分析。那么,同样的日志文件,我们来体验一下finditer函数,算是温故知新吧。我学习正则表达式的经验就是得一次一次反复学习,反复练习哦。

建一个实验文件夹。日志内容,保存成log.txt。

Sep 26 2021 23:11:02-08:00 Layer3Switch-1 L2IFPPI/4/MFLPVLANALARM:OID 1.3.6.1.4.1.2011.5.25.160.3.7 MAC move detected, VlanId = 54, MacAddress = 0000-5e00-0136, Original-Port = GE0/0/1, Flapping port = GE0/0/2. Please check the network accessed to flapping port.
Sep 26 2021 23:11:08-08:00 Layer3Switch-1 L2IFPPI/4/MFLPVLANALARM:OID 1.3.6.1.4.1.2011.5.25.160.3.7 MAC move detected, VlanId = 54, MacAddress = 0000-5e00-0136, Original-Port = GE0/0/1, Flapping port = GE0/0/2. Please check the network accessed to flapping port.
Sep 26 2021 23:11:10-08:00 Layer3Switch-1 L2IFPPI/4/MFLPVLANALARM:OID 1.3.6.1.4.1.2011.5.25.160.3.7 MAC move detected, VlanId = 54, MacAddress = 0000-5e00-0136, Original-Port = GE0/0/2, Flapping port = GE0/0/3. Please check the network accessed to flapping port.
Sep 26 2021 23:11:15-08:00 Layer3Switch-1 L2IFPPI/4/MFLPVLANALARM:OID 1.3.6.1.4.1.2011.5.25.160.3.7 MAC move detected, VlanId = 54, MacAddress = 0000-5e00-0136, Original-Port = GE0/0/3, Flapping port = GE0/0/1. Please check the network accessed to flapping port.

Python代码内容,保存成lab5.py。

import re

regex = (r'.*VlanId = (\d+), '
         r'MacAddress = \S+, '
         r'Original-Port = (\S+), '
         r'Flapping port = (\S+)\.')

ports = set()

with open('log.txt') as f:
    for each_match in re.finditer(regex, f.read()):
        vlan = each_match.group(1)
        ports.add(each_match.group(2))
        ports.add(each_match.group(3))

print('Loop between ports {} in VLAN {}'.format(', '.join(ports), vlan))

我们把代码调整成finditer函数。大家可以回过头对比一下search函数、match函数同样的日志解析例子。Finditer函数并不是逐行匹配,而是一次匹配,效率会高不少。同时,无论Finditer函数处理的结果如何,有无匹配中,其始终返回一个可迭代对象而不是None,因此也不用再做是否匹配得中的if判断了。我们试跑一下脚本看看吧。

实验总结

学点新的,复习旧的,再复习就的过程中再添点新的,一步一步往前拱,知识才得以巩固和拓展。除了Finditer函数的使用外,我们还点了一下列表推导式,这个如果学有余力想进阶的童鞋们可以继续深挖,Python中不仅有列表推导式,还有字典推导式等各种推导式。推导式除了简洁炫酷外,效率也比较高,但我始终觉得看起来有点绕。

最近思考,网络运维自动化我们用python拿着paramiko、netmiko、nornir等去连接设备采集信息和下发配置。大家想想,在现实生产环境中,有多少普通运维网工能自主地在大型生产网中找到点位部署、使用这些“联机”手段呢?网工自己写的未经严格测试的脚本代码能随随便便去操控设备呢?其实很难很难。真正的生产网都是分权分域有各种安全管控和审计的,这一点国内国外都如此的。我想,小型园区网的运维工程师、部分大型网络某些岗位的运维工程师是有条件尝试,但是最开始能从show或display等不影响设备配置的任务做起,逐步展开。然后,目前没机会实际开展网络运维自动化的网工呢?通过实验网或模拟器,掌握新技能,说不定哪天能用上呢?简历面试舔砖加瓦?处理这些我想更重要的是把握新趋势,理解自动化运维思想,把这种思想应用到日常的运维工作、事务工作、甚至日常生活。回到实际的工作,抛开“联机”问题,离线方面,网络运维自动化其实已经能做很多事情了,实施脚本制作,配置回显解析,配置核对,线上线下台账比对,资源管理核对等。好吧,先来学习掌握正则表达式吧哈哈。


感谢阅读,欢迎关注点赞收藏评论交流。

2021年11月于广东汕头

编辑于 2021-12-03 14:33