Python学习之re.compile与findall

在做项目的过程中,有时候需要再一个几万行的代码里找到某个信号,并且把它拷贝出来用。信号的定义格式是相同的,但是编号不相同,如下图所示。按道理说可以利用vim的查找功能一个个找,然后一个个地手工拷贝。如果电路有修改和迭代,查找+拷贝的方式太费时费力了,所以想到用python来处理这种有规律的、重复性的工作。

re.compile()

用正则表达式可以匹配到我想找出的信号,使用正则表达式匹配之前将re模块导入。

import re

re.compile()函数用于编译正则表达式,生成一个Pattern对象,供其他函数使用。re.compile的语法格式如下:

re.compile(pattren[, flag])

其中pattern为一个字符串形式的正则表达式;flag是可选的,用于设置匹配模式。常见的几种匹配有:

re.compile(r'\d+')			// 用于匹配数字
re.compile(r'[a-z]+')		// 用于小写字母
re.compile(r'[A-Z]+')		// 用于大写字母
……
re.compile(r'a.b')			// 符号“.”用来匹配除了换行符以外的任意字符
re.compile(r'a*b')			// 符号“*”前面的字符出现0次或以上(即以后面的字符为准)
re.compile(r'a.*b')			// 符号“.*”贪婪匹配:以a为开始以b为结束的所有内容
re.compile(r'a.*?b')			// 符号“.*?”非贪婪匹配:只要遇到以a为开始以b为结束就匹配
re.compile(r'a.*?(?=b)')		// 与上一条相同,区别在于:匹配结果不包括b
……
匹配规则不是Python特有的,更多匹配方式可见正则表达式的匹配规则
注意转义字符的匹配

转义字符是指在字母前加上反斜杠来表示的一些不能显示的ASCII字符,最常见换行符\n。文本中很可能出现类似的用转义字符表示的特定字符,举个例子:not important string... N_XI_pix_db0\<1\>\/XI_pix_even\/XI_dvs ...omit these words
如果要在文本中匹配带有转义字符的字符串N_XI_pix_db0\<1\>\/XI_pix_even\/XI_dvs,反斜杠自身也是待匹配字符,匹配的pattern可以用两种方式表示:
1.每个特殊字符前都加上反斜杠——N_XI_pix_db0\\\<1\\\>\\\/XI_pix_even\\\/XI_dvs
2.每个特殊字符都用中括号括起来——N_XI_pix_db0[\][<]1[\][>][\][/]XI_pix_even[\][/]XI_dvs

findall

与re.compile()配合使用发函数或方法有re.match()、re.search()、re.findall()、re.sub()。其区别如下:

str = `not important string... N_XI_pix_db0\<1\>\/XI_pix_even\/XI_dvs ...omit these words`
pattern = re.compile(r'N_XI_pix_db0\\\<1\\\>\\\/XI_pix_even\\\/XI_dvs')

re_object = pattern.match(str)		// 从字符串的起始位置匹配,如果起始位置的字符串匹配不成功则返回"None"
re_object = pattern.search(str)		// 匹配整个字符串,并返回第一个匹配成功的项,否则返回"None"
result = re_object.group()			// 返回一个包含所有匹配的子字符串的元组

result = pattern.findall(str)		// 找到所有匹配的子项并返回一个列表,如果没有匹配项则返回空列表
result = pattern.sub('replacement', str)	// 用replacement替换所有的匹配项
  • 注意:上述match与search方法返回的如下图所示的正则匹配的对象,而不是匹配的字符串!若要返回匹配的内容,还要用group()方法。
    匹配对象
    我选择了findall,满足匹配的项很多,只需要保留一个,想着用pattern.findall(str)[0]返回首个匹配项。但是,假设一个匹配项都没有,则会返回空列表,也就是不存在首项[0],因此这样写会报错。

python script

由于我要找的信号有很多个,我采用的方法是先把待匹配的所有信号放在一个字符串列表中,通过循环再逐个访问和匹配。这样做会把文本遍历很多遍,用findall方法会花费很长的时间去匹配。后续发现用search方法也能满足我的需求,因为search返回就是单个匹配项。两种方式的结果完全相同,而且search方法快了很多!

findall script
import re

sig_list = []
pattern_list = ['str1','str2','str3',...,'strN']

with open('/path/netlist','r') as f_in:
	rcc_file = f_in.read();
	for i in range(len(rcc_file)):
		pattern = re.compile(pattern_list[i])
		sig_org = pattern.findall(rcc_file)
		if(len(sig_org) == 0):
			print(pattern_list[i], 'is not found!')
		else:
			sig_recover = sig_org[0].replace('\\','')
			sig_probe = 'special string' + sig_recover
			sig_list.append(sig_probe)
		
sig_write = '\n'.join(sig_list)

with open('/path/probe','w') as f_out:
	f_out.write(sig_write)
	print('Singal collection is done.')
  • replace方法是为了将转义字符的反斜杠去掉,使N_XI_pix_db0\<1\>\/XI_pix_even\/XI_dvs恢复成N_XI_pix_db0<1>/XI_pix_even/XI_dvs
  • 符号+将完成固定字符与找到的匹配项拼接起来,生成信号探测的tcl脚本
  • append方法在原列表sig_list的末尾位置添加新的匹配项
  • join方法在原列表中的每个字符串末尾加一个换行符,方便后续按行写入文件
  • 推荐用with open() as f的方式操作文件,确保文件的正确关闭
search script
import re

sig_list = []
pattern_list = ['str1','str2','str3',...,'strN']

with open('/path/netlist','r') as f_in:
	rcc_file = f_in.read();
	for i in range(len(rcc_file)):
		pattern = re.compile(pattern_list[i])
		sig_org = pattern.search(rcc_file)
		if sig_org :
			sig_string = sig_org.group()
			sig_recover = sig_org[0].replace('\\','')
			sig_probe = 'special string' + sig_recover
			sig_list.append(sig_probe)
		else:
			print(pattern_list[i], 'is not found!')
		
sig_write = '\n'.join(sig_list)

with open('/path/probe','w') as f_out:
	f_out.write(sig_write)
	print('Singal collection is done.')
  • 此处判断是否找到对应的信号时,是否可以用以下程序中的if(sig_org == '')?答案是否定的。因为如果某个信号不存在,也就是匹配不成功,返回的是None,而python中的''表示空字符串;下面的程序进入else分支,如果用sig_org.group()方法返回元组内容,程序报错并提示'NoneType' object has no attribute 'group'
  • None是一种特殊的常量,其类型为NoneType
		// wrong code
		if (sig_org == ''):
			print(pattern_list[i], 'is not found!')
		else:
			sig_string = sig_org.group()
			sig_recover = sig_org[0].replace('\\','')
			sig_probe = 'special string' + sig_recover
			sig_list.append(sig_probe)

reference

菜鸟教程python link
Python find all详解 link

  • 2
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值