正则表达式(re模块)知识点记录

在这里记录一下最近学习到的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模块的常用用法

  1. 匹配(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'>
  2. 查找
    在给定字符串中查找符合正则表达式的描述的子字符串。

    • 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
2
3
4
import re
key = '123456789'
reg = '(0-9)'
re.compile(reg).match(key) # 什么都匹配不到

什么都匹配不到,因为(0-9)代表的是0-9这个字符串

中括号[]

中括号匹配字符组内的字符,比如

1
[a-zA-Z0-9]

这个正则表达式实际上只匹配一个字符,但是这个字符可以是大小写字母或者数字。

1
2
3
4
5
>>> import re
>>> key = '123456789'
>>> reg = '[a-zA-Z0-9]'
>>> re.compile(reg).match(key)
<_sre.SRE_Match object; span=(0, 1), match='1'>

如果加上+号,就代表匹配一个或多个

1
2
3
>>> reg = '[a-zA-Z0-9]+'
>>> re.compile(reg).match(key)
<_sre.SRE_Match object; span=(0, 9), match='123456789'> # 所以这里一直匹配到底

大括号{}

大括号代表匹配次数,匹配在它之前表达式匹配出来的元素出现的次数。

  • {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,….就代表第二个第三个子表达式。

所以回溯引用是正则表达式内的一个“动态”的正则表达式,让你根据实际的情况变化进行匹配。

参考