在这里记录一下最近学习到的Python正则表达是的知识点
正则表达式是什么?
正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
通俗来讲,可以把正则表达式理解为类似于一门计算机语言,不过它是用来描述符合某些规则的字符串的。
基础
- Python 中正则表达式模块是
re
,只要import re
就好 最简单的正则表达式就是我们想要匹配的字符串,比如
1
2
3
4
5>>> import re
>>> key = 'javapythonc++'
>>> reg = 'python'
>>> re.compile(reg).findall(key)
['python']
re模块的常用用法
匹配(match)
判断给定的字符串是否符合正则表达式的描述。
如果match,就会返回一个_sre.SRE_Match
对象,否则返回空1
2
3
4
5>>> import re
>>> key = 'python'
>>> reg = 'python'
>>> re.compile(reg).match(key)
<_sre.SRE_Match object; span=(0, 6), match='python'>查找
在给定字符串中查找符合正则表达式的描述的子字符串。search
判断是否能找到符合标准的子字符串findall
找出所有的符合标准的子字符串
1
2
3
4
5
6
7
>>> import re
>>> key = 'javapythonjavapython'
>>> reg = 'python'
>>> re.compile(reg).search(key) # 是否能找到'python'
<_sre.SRE_Match object; span=(4, 10), match='python'>
>>> re.compile(reg).findall(key) # 找到所有的 'python'
['python', 'python']
常用正则表达式的元字符及其作用
元字符 | 说明 | |
---|---|---|
. | 代表任意字符 | |
\ | 逻辑或操作符 | |
[ ] | 匹配内部的任一字符或子表达式 | |
[\^] | 对字符集和取非 | |
- | 定义一个区间 | |
\ | 对下一字符取非(通常是普通变特殊,特殊变普通) | |
* | 匹配前面的字符或者子表达式0次或多次 | |
*? | 惰性匹配上一个 | |
+ | 匹配前一个字符或子表达式一次或多次 | |
+? | 惰性匹配上一个 | |
? | 匹配前一个字符或子表达式0次或1次重复 | |
{n} | 匹配前一个字符或子表达式 | |
{m,n} | 匹配前一个字符或子表达式至少m次至多n次 | |
{n,} | 匹配前一个字符或者子表达式至少n次 | |
{n,}? | 前一个的惰性匹配 | |
^ | 匹配字符串的开头 | |
\A | 匹配字符串开头 | |
$ | 匹配字符串结束 | |
[\b] | 退格字符 | |
\c | 匹配一个控制字符 | |
\d | 匹配任意数字 | |
\D | 匹配数字以外的字符 | |
\t | 匹配制表符 | |
\w | 匹配任意数字字母下划线 | |
\W | 不匹配数字字母下划线 |
特别的,我们要记住\
能够把普通的字符变特殊,特殊字符变普通。
比如.
代表匹配所有字符, \.
则代表单纯的一个点d
代表单纯的d这个字母,\d
则代表0-9的数字
小括号(),中括号[],大括号{}的区别
小括号()
小括号形成子表达式,比如
1 | import re |
什么都匹配不到,因为(0-9)
代表的是0-9
这个字符串
中括号[]
中括号匹配字符组内的字符,比如
1 | [a-zA-Z0-9] |
这个正则表达式实际上只匹配一个字符,但是这个字符可以是大小写字母或者数字。
1 | >>> import re |
如果加上+
号,就代表匹配一个或多个
1 | >>> reg = '[a-zA-Z0-9]+' |
大括号{}
大括号代表匹配次数,匹配在它之前表达式匹配出来的元素出现的次数。
{n}
出现n次{n,}
匹配最少出现n次{n,m}
匹配最少出现n次,最多出现m次
进阶用法
向前向后查找
简单来说,就是你要匹配的字符串是XX
,但是必须满足形式是AXXB
这样的字符串,那么正则表达式就可以写成这样
1 | p=r"(?<=A)XX(?=B)" |
?<=
代表字符串前必须要有A
, 即前缀要求?=
代表字符串后必须要有B
,即后缀要求
本质上来说,向前查找和向后查找其实是匹配整个字符串,即AXXB
,但返回时仅仅返回一个XX
。也就是说,如果你愿意,完全可以避开向前向后查找的方式,直接匹配带有前后缀的字符串,然后做字符串切片处理。
回溯引用
比如我们要匹配形如<h1>hello world</h1>
这样的字符串,同时不仅限于<h1>
,而是获取<h1>
到<h6>
的。
那我们就可以写成
1 | r"<h[1-6]>.*?</h[1-6]>" |
但是如果遇到像这样的特殊情况,就不好玩了
1 | <h1>hello world</h3> |
为了保证hello world
前后都是一样的,我们可以用到回溯引用,就像这样
1 | r"<h([1-6])>.*?</h\1>" |
看到\1
了吗?原本那个位置应该是[1-6]
,但是我们写的是\1
,我们之前说过,转义符\
干的活就是把特殊的字符转成一般的字符,把一般的字符转成特殊字符。普普通通的数字1被转移成什么了呢?在这里1表示第一个子表达式,也就是说,它是动态的,是随着前面第一个子表达式的匹配到的东西而变化的。比方说前面的子表达式内是[1-6]
,在实际字符串中找到了1
,那么后面的\1
就是1,如果前面的子表达式在实际字符串中找到了2,那么后面的\1
就是2。
类似的,\2,\3,….就代表第二个第三个子表达式。
所以回溯引用是正则表达式内的一个“动态”的正则表达式,让你根据实际的情况变化进行匹配。