在做项目的过程中,有时候需要再一个几万行的代码里找到某个信号,并且把它拷贝出来用。信号的定义格式是相同的,但是编号不相同,如下图所示。按道理说可以利用vim的查找功能一个个找,然后一个个地手工拷贝。如果电路有修改和迭代,查找+拷贝的方式太费时费力了,所以想到用python来处理这种有规律的、重复性的工作。
用正则表达式可以匹配到我想找出的信号,使用正则表达式匹配之前将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
。
与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替换所有的匹配项
pattern.findall(str)[0]
返回首个匹配项。但是,假设一个匹配项都没有,则会返回空列表,也就是不存在首项[0]
,因此这样写会报错。由于我要找的信号有很多个,我采用的方法是先把待匹配的所有信号放在一个字符串列表中,通过循环再逐个访问和匹配。这样做会把文本遍历很多遍,用findall方法会花费很长的时间去匹配。后续发现用search方法也能满足我的需求,因为search返回就是单个匹配项。两种方式的结果完全相同,而且search方法快了很多!
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
的方式操作文件,确保文件的正确关闭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)
菜鸟教程python link
Python find all详解 link