![eb859384f1ff1ad2f1930c8b884aaf05.png](https://i-blog.csdnimg.cn/blog_migrate/781db07096aa5bda6dc02eb6977e5e99.jpeg)
别怀疑,没有走错片场!掌握文本处理的基本技能对于电路设计者来说十分必要,比如网表替换、仿真结果提取等,都需要一定的文本处理能力,那么面对数千行甚至数万行的文本内容你会如何操作呢?
首先小目同学要跟大家介绍的是所有编程中(不仅仅是python)文本处理的利器——正则表达式。
什么是正则表达式
如果有了解过编程语言或者文本处理的同学肯定或多或少地听说过正则表达式,相信也有不少人学习过正则表达式。
那么,什么是正则表达式呢?在编写处理字符类的程序时,经常会有查找符合某些复杂规则的字符串的需要,正则表达式就是用于描述这些规则的工具。正则表达式是一个特殊的字符序列,它能帮助用户检查一个字符串是否与需要的某种规则匹配。
正则表达式很有用,大多数现代文本编辑器和信息查找工具(如Word 或 Cadence 中的查找工具),都可以实现依据正则表达式查找和替换的功能,学习使用正则表达式可以大大提高文本处理的效率,节约大量时间。
实际上我们在Linux终端经常会使用正则表达式,例如:
[IC@IC lib]$ ls *.so
显示所有以「.so」为结尾的文件,其中「*」号表示:匹配所有的字符。所以上面的命令可以显示出该文件夹下所有后缀是「.so」的文件,而不会理会后缀前的内容,因为「*」号匹配所有内容。
![6efaa9fbbd7465eef6009a1a5bacfe5b.png](https://i-blog.csdnimg.cn/blog_migrate/e672899d76ba1dbafbc594cfbecbceb0.jpeg)
与上面的「*」号类似,正则表达式也是用来进行文本匹配,只不过可以精确地描述用户的需求,当然也会更复杂一些。
正则表达式的实例
像所有的编程语言学习一样,学习正则表达式的最好方法是从实例开始,理解实例之后再对实例子进行修改,那么必然会事半功倍:
- 匹配一个具体字符串:ICSkillSharing;
- 匹配m-n位的数字:d{m,n};
- 匹配非负的浮点数(比如器件尺寸):d+.d+|.d+|d+;
- 匹配由大写字母组成的字符串:[A-Z]+;
- 匹配由英文字母组成的字符串:[A-Za-z]+;
- 匹配如(0376-1234567, 010-12345678)格式的电话号码:d{3}-d{8}|d{4}-d{7};
可能现在还看不懂正则表达式如何起作用,但是按照上面的格式可以匹配固定格式的字符串或者字符。
不同编程语言使用正则表达式的方法可能略有差异,但是正则表达式的基本内容大同小异,建议在使用正则表达式之前可以使用「在线正则表达式测试工具」进行测试,方便、快捷、高效,小目同学使用的是菜鸟工具提供的正则表达式测试服务。
![def14f55aac00e1351224bcbb0187012.png](https://i-blog.csdnimg.cn/blog_migrate/1260ea48f086a97786406fdb71d798ea.jpeg)
部分网站和可以根据测试内容生成对应的程序,比如使用 python 语言匹配器件尺寸可以写成如下格式(但是简单获得数值意义并不大):
import re
pattern = re.compile(r'd+.d+|.d+|d+')
str = 'w=0.35u l=500n w=5u l=.6u w=4.6u l=1u'
print(pattern.findall(str))
正则表达式的常用元字符
下表包含了正则表达式常用的元字符列表以及它们在正则表达式上下文中的行为,对于不常用的正则表达式很容易忘记,所以不必记住所有元字符,只需要在使用的时候查表即可(部分内容针对python, 但是大部分编程语言正则表达式元字符基本一致)。
正则常用的元字符
转义字符 | |
将下一个字符标记为一个原义字符等,例如,'n'匹配一个换行符,'' 匹配 '' 而 '(' 则匹配 '('。 | |
常用字符匹配 | |
. | 匹配除 'n' 之外的任何单个字符,如果需要匹配包括 'n' 在内的任何字符,可以使用如 '[.n]' 的模式。 |
w | 匹配任何字母、数字、下划线字符,等价于' [A-Za-z0-9_]'. |
s | 匹配任何空白字符,包括空格、制表符、换页符等等,等价于 '[ fnrtv]'. |
d | 匹配一个数字字符,等价于 '[0-9]'. |
b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'hib' 可以匹配'abchi' 中的 'hi',但不能匹配 'abhic' 中的 'hi'. |
^ | 匹配字符串的开始位置,'^spam' 意味着字符串必须以 'spam' 开始。 |
$ | 匹配字符串结束的位置,'spam$' 意味着字符串必须以 'spam' 结束。 |
[a-z] | 匹配指定范围内的任意字符,例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母。 |
[adfsg] | 匹配所包含的任意一个字符,例如,'[adfsg]' 可以匹配 'ha' 中的 'a'. |
x|y | 匹配 x 或 y, 例如,'x|abc' 能匹配 'x' 或 'abc', '(a|b)cd' 则匹配 'acd' 或 'bcd'. |
常用的限定字符 | |
* | 匹配前面的表达式任意次,例如,he* 能匹配 'h' , 'he' 以及'heee'等,等价于{0,}. |
+ | 匹配前面的表达式一次或多次,例如,'he+' 能匹配 'he' 以及 'hee',但不能匹配 'h', + 等价于 {1,} |
? | 匹配前面的子表达式零次或一次。例如,'he?' 可以匹配 "he" 或'h', '?' 等价于 {0,1}. |
{n} | 匹配确定的 n 次,n 是一个非负整数。例如,'e{2}' 不能匹配 'hheh'中的 'e',但是能匹配 'hheeh' 中的两个 'e'. |
{n,} | 至少匹配n 次,n 是一个非负整数。例如,'e{2,}' 不能匹配 'hheh' 中的 'e',但是能匹配 'hheeeeh' 中的 'eeee'. |
{n,m} | 最少匹配 n 次,最多匹配 m 次,其中n <= m 且m 和 n 均为非负整数。例如,'e{1,3}' 将匹配 'hheeeeh' 中的前三个 e. |
常用的反义字符 | |
W | 匹配任意不是字母、数字、下划线的字符,等价于 [^A-Za-z0-9_]. |
S | 匹配任何非空白字符,等价于 [^ fnrtv]. |
D | 匹配一个非数字字符,等价于 [^0-9]. |
B | 匹配非单词边界,例如, 'hiB' 可以匹配'abhic' 中的 'hi',但不能匹配 'abchi' 中的 'hi'. |
[^a-z] | 匹配任何不在指定范围内的字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。 |
[^adfsg] | 匹配未包含的任意字符,例如,'[^adfsg]' 可以匹配 'habcdefgh' 中除了 'adfsg' 以外的所有字符。 |
利用小括号分组 | |
(pattern) | 添加括号在正则表达式中创建“分组”,例如将区号从电话号码中分离:(d{3})-(d{7}), 然后可以使用 group() 匹配对象方法,从一个分组中获取匹配的文本。 |
(?:pattern) | 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。 |
(?=pattern) | 零宽度正预测先行断言,它断言此位置的后面能匹配pattern, 但不包含此位置,如:(?=d)a, 返回匹配字符串中以数字为开头的a字符。 |
(?<=pattern) | 零宽度正回顾后发断言,它断言此位置的前面能匹配pattern, 但不包含此位置,如:(?<=d)a, 返回匹配字符串中以数字为开头的a字符。 |
(?!pattern) | 零宽度负预测先行断言,它断言此位置的后面不能匹配pattern且不包含此位置,如:a(?!d),返回匹配字符串中不以数字结尾的a字符。 |
(?<!pattern) | 零宽度负回顾后发断言,它断言此位置的前面不能匹配pattern且不含此位置,如:(?<!d)a, 返回匹配字符串中不以数字开头的a字符。 |
以上内容可以在使用正则表达式的时候作为参考,其中比较难理解的是「零宽度断言」,不过结合解释和网上的一些实例学习也很容易理解。
正则表达式的运算符优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。相同优先级的从左到右进行运算,不同优先级的运算先高后低,下表从最高到最低说明了各种正则表达式运算符的优先级顺序:
正则表达式优先级顺序表
元字符 | 描述 |
转义字符 | |
(),[] | 圆括号分组和方括号限定 |
*, +, ?, {n}, {n,}, {n,m} | 限定符 |
^, $, 任何元字符、任何字符 | 优先级根据位置顺序确定 |
| | 分支条件 |
正则表达式的贪婪与非贪婪
默认情况下正则表达式的匹配是贪婪的,这个意思是当正则表达式中包含能接受重复的限定符时,通常匹配的结果是:在使整个表达式能得到匹配的前提下,尽可能多地匹配字符。
比如:'b.*y',它将会匹配最长的以'b'开始,以'y'结束的字符串。如果用它来匹配 'bbbybboy'的话,它会匹配整个字符串,正则表达式的这种匹配特性被称为贪婪匹配。
有时,可能更需要非贪婪匹配,也就是在满足匹配条件的情况下尽可能少地匹配字符。前面列出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号「?」即可。
比如:'b.*?y',它将会匹配最短的以'b'开始,以'y'结束的字符串。如果用它来匹配'bbbybboy'的话,它会匹配到 'bbby'(第1到第4个字符)和 'bboy'(第5到第8个字符)。
正则表达式的非贪婪匹配
元字符 | 描述 |
*? | 匹配前面的表达式任意次,但尽可能少的次数 |
+? | 匹配前面的表达式1次或多次,但尽可能少的次数 |
?? | 匹配前面的表达式0次或1次,但尽可能少的次数 |
{n,m}? | 匹配前面的表达式n到m次,但尽可能少的次数 |
{n,} | 匹配前面的表达式n次以上,但尽可能少的次数 |
关于正则表达式的使用很多网站也有详细讲解,这里推荐「正则表达式30分钟入门教程」和「W3Cschool的相关教程」,希望各位同学都能够熟练掌握正则表达式的使用技巧,早日体会到使用正则表达式的乐趣。
正则表达式的学习技巧在于多看、多写、多用,本次主要是介绍正则表达式的规则,下一次会通过实践展示一下python正则表达式的使用。
简介
作者:小目(wx:student_xiaomu)
微信公众号:ICSkillSharing,是一个共同学习的平台,分享最新IT类资讯、原创内容、IC中脚本语言的教程与使用心得、模拟IC新手在学习过程中遇到的问题等,与大家一起成长进步!