首页 > 编程笔记 > Python笔记 阅读:8

Python re模块seach()和findall()的用法(附带实例)

re 是 Python 内置的标准模块,无须安装,直接 import 即可使用,常用的两个函数是 search() 和 findall()。

Python search()函数

search() 函数会在给定的字符串中匹配并识别符合正则表达式的文本,它有两个重要参数:pattern 和 string,分别代表正则表达式和给定的字符串文本。

调用 search() 函数时,如果匹配成功,则返回 Match 对象;如果匹配失败,则返回 None。

Match 对象包含匹配到的字符串的相关信息,例如实际匹配到的字符串内容、起始位置等。调用 Match 对象的 group() 方法,无须传入任何参数,就可以获取匹配到的字符串整体。

使用 search() 函数在文本中匹配正则表达式时,要考虑识别成功和失败两种情况,因为只有识别成功后才会返回 Match 对象,才可以接着调用其 group() 方法获取识别的文本。

下面用一个实例演示 search() 函数的基本使用:
import re
# 文本
text = 'interface Ehternet1/5 is up'
# 正则表达式,提取端口信息
intf_pattern = 'Ehternet\d+/\d+'
# 调用re模块的search函数,使用正则表达式intf_pattern在指定的文本中匹配识别
interface_match = re.search(intf_pattern, text)
# 如果search返回的结果不为空,那么代表匹配成功
if interface_match:
    # 获取整体的匹配
    intf = interface_match.group()
    print('识别出符合正则表达式的字符串:', intf)
else:
    print('字符串中开始无法识别出符合正则表达式的子串')
程序的功能是从指定文本中提取端口的相关信息,其关键在于正则表达式的书写,要找到端口信息特征中的不变与变的内容:不变的内容使用普通字符,变的内容使用元字符。端口名称的前缀是不变的,端口的编号是在不断变化的,所以正则表达式可以设计为“Ehternet\d+/\d+”。

程序的运行结果如下:

识别出符合正则表达式的字符串:Ehternet1/5

上面只是一个简单示例,实际使用中用户更希望提取出准确的数据。例如,用户希望在上面实例中提取软件版本号,但是最终匹配到的内容中包含了 Version 字符串。这种情况可以用括号将版本号部分的正则表达式包裹起来,并将软件版本的正则表达式升级为“Version (\S+)”,这样正则表达式在匹配识别整体的同时,(\S+) 会去识别提取软件版本号数据。

像“(\S+)”这种被括号包裹住的正则表达式被称为子表达式。在一段正则表达式中,子表达式可以有多个。在调用 search() 函数时,如果正则表达式中含有子表达式,当匹配成功后,直接调用 Match 对象的 group() 方法(不传参)获取识别的整段文本;当调用 group() 方法时,传入整数 1、2、3 会提取对应排序的子表达式识别到的文本。

通过编写子表达式,正则表达式可以既匹配整体又识别局部。search() 函数在子表达式场景下的使用如下面的实例:
import re
# 文本
show_text = """<netdevops>display version
Huawei Versatile Routing Platform Software
VRP (R) software, Version 8.180 (CE6800 V200R005C10SPC607B607)
Copyright (C) 2012-2018 Huawei Technologies Co., Ltd.
HUAWEI CE6800 uptime is 0 day, 0 hour, 3 minutes
"""
# 调用search函数,正则表达式中含有子表达式
version_match = re.search('Version (\S+)', show_text)
if version_match:
    # 调用group,不传参,获取匹配的整体
    version_all_text = version_match.group()
    print('识别到的整段文本:',version_all_text)
    # 调用group,传参1,获取第一个子表达式识别的文本
    version = version_match.group(1)
    print('识别到的软件版本号(第一个子表达式):',version)
程序中的正则表达式含有子表达式,且排序是第一个,通过调用 Match 对象的 group() 方法,传入对应序号 1 就可以提取出版本号数据。代码运行结果如下:

识别到的整段文本: Version 8.180
识别到的软件版本号(第一个子表达式):8.180


在 re 模块中还有一个 match() 函数,它的参数与 search() 函数一致。二者在功能上的区别是:
读者了解二者的区别即可,search() 函数更加适合提取数据。

Python findall()函数

一旦在文本中找到了符合正则表达式的文本,search() 函数就停止继续匹配识别。当给定的文本类似于端口简表、MAC 表、ARP 表等配置回显时,如果用户希望一次提取出所有的信息,这时就需要用到 findall() 函数。

findall() 函数的参数与 search() 函数的参数完全一致,第一个参数是正则表达式 pattern,第二个参数是给定的文本字符串 string。

findall() 函数会把所有匹配识别的文本全部提取出来,将它们组装成一个列表并返回:
下面的实例演示了 findall() 函数的基本使用。
import re
# 文本
text = '''interface Ehternet1/5 is up
interface Ehternet1/6 is up
interface Ehternet1/7 is down
'''
# 正则表达式
intf_pattern = 'Ehternet\d+/\d+'
# 调用findall函数识别所有数据
intfs = re.findall(intf_pattern, text)
print(intfs)
程序中的正则表达式没有子表达式,所以 findall() 函数返回的结果是字符串列表,运行结果如下:

['Ehternet1/5', 'Ehternet1/6', 'Ehternet1/7']


调用 findall() 函数时,如果正则表达式中含有子表达式,那么 findall() 函数返回的是元组列表,元组的成员是子表达式提取到的数据。

在上面的实例程序中,如果将正则表达式“Ehternet\d+/\d+”修改为“Ehternet(\d+)/(\d+)”,就可以将端口号中的槽位和索引信息取出,对应的代码运行结果则会变为:

[('1', '5'), ('1', '6'), ('1', '7')]

相关文章