Python中正则表达式的学习记录

这篇文章记录了python中的正则匹配规则的相关语法,当然也不局限于python中,大部分是通用的,这些规则个人 认为只需记住常用的两三个,当你真正大量使用的时候,再去查阅,完全ok,不要浪费时间苦恼怎么去记住那多么的匹配规则。

1、纯字符串匹配:

这一类是最简单的,也是字符串操作可以代替的,但是我们还是以这种匹配开始我们的教程,介绍正则的基本思想。

1
2
3
4
import re
str = "hello,everyone,I am HelloHaibo,thank u for watching my blog"
pattern = re.compile(r'Haibo')
content = re.findall(pattern,str)
1
content: ['Haibo']

说明在str中找到了我们需要的纯字符串,如果我把pattern = re.compile(r'Haibo')换成pattern = re.compile(r'haibo'),则会提示没有找到元素,说明匹配的内容与你事先定义的是要完全匹配的,区分大小写。

事实上述做法并没有太大意义(对于纯字符串正则匹配来说),普通的字符串操作即可满足要求,并且可能更有效的解决问题。但是正则表达式的灵活性却是字符串操作不可比拟的,下面的几种匹配是我们常用的。

2、单字符匹配:

其实我们大多数时候并不知道我们匹配的字符具体是什么,我们只知道他们是属于那一类,像它属于数字啊,小写字母啊,特殊字符啊这样的,这样就需要我们正则表达式出马。我们来先看看单字符匹配。

第一种: 单一个 .,匹配任何一个字符,但是除了\n(换行符)

1
2
3
4
import re
str = "hello,everyone,I am HelloHaibo,thank u for watching my blog"
pattern = re.compile(r'.ello')
content = re.findall(pattern,str)
1
1
content: ['hello', 'Hello']

说明 .Hh都匹配到了,其实就算字符串里存在这样的,fellodello8ello这样字符串,它也是能查找到的。但是一个 . 只匹配一个任意字符,想匹配多个任意字符就要写多个.

第二种: \d\D, 其中\d匹配单一个纯数字,\D匹配除了数字之外的字符,两个集合刚好互为补集

1
2
3
4
import re
str2 = "1 + 2 = 3,yeah"
pattern = re.compile(r'\d')
content = re.findall(pattern,str2)
1
1
content: ['1', '2', '3']

可见\d把数字都匹配出来了,让我们再用\D匹配一下:

1
2
3
4
import re
str2 = "1 + 2 = 3,yeah"
pattern = re.compile(r'\D')
content = re.findall(pattern,str2)
1
content: [' ', '+', ' ', ' ', '=', ' ', ',', 'y', 'e', 'a', 'h']

可见,\D把除了数字以外的全部都匹配了。

第三种: \w \W,其中\w匹配字符a-z A-Z 0-9\W反之

1
2
3
4
import re
str2 = "1 + 2 = 3,Yeah"
pattern = re.compile(r'\w')
content = re.findall(pattern,str2)
1
content: ['1', '2', '3', 'Y', 'e', 'a', 'h']

\w把字符串里的数字,小写字母,大写字母都匹配出来了。

1
2
3
4
import re
str2 = "1 + 2 = 3,Yeah"
pattern = re.compile(r'\W')
content = re.findall(pattern,str2)
1
content: [' ', '+', ' ', ' ', '=', ' ', ',']

\W把除了数字,小写字母,大写字母以外的都匹配出来了。

3、单字符匹配:

第一种: []方括号,代表字符集合

第二种: -连字符,标识一个范围(对应ASCII表)0-4,表示匹配,0 1 2 3 4,它需要跟[]配套使用。

1
2
3
4
import re
str2 = "1 + 2 = 3,yeah"
pattern = re.compile(r'[0-4]')
content = re.findall(pattern,str2)
1
1
content: ['1', '2', '3']
1
2
3
4
import re
str2 = "1 + 2 = 3,yeah"
pattern = re.compile(r'[a-z]')
content = re.findall(pattern,str2)
1
content: ['y', 'e', 'a', 'h']

第三种: * ? + 这三个字符用的几率非常大,下面分别举例说明一下。

  • * 匹配前一个字符零次或者无限次
1
2
3
4
import re
str1 = "http https httpes httpsss"
pattern = re.compile(r'https*')
content = re.findall(pattern,str1)
1
content: ['http', 'https', 'http', 'httpsss']
  • + 表示匹配前面的字符一次或者无限次
1
2
3
4
import re
str1 = "http https httpes httpsss"
pattern = re.compile(r'https+')
content = re.findall(pattern,str1)
1
content: ['https', 'httpsss']

可以看出http没有被匹配上,因为s至少要匹配一次

  • ? 表示匹配前一个字符零次或者一次
1
2
3
4
import re
str1 = "http https httpsss"
pattern = re.compile(r'https?')
content = re.findall(pattern,str1)
1
content: ['http', 'https', 'https']

结果怎么出现了两个https?可见,httpsss中的https部分也被匹配到了,这是我们不想遇到的,所以我们有时候需要规定匹配的次数,而并不是让算法自己无休止的匹配下去。

第四种:{m,n}匹配前一个字符m-n次,即m-n中的任意次数都行,包括m和n,将上述代码稍加修改。

1
2
3
4
import re
str1 = "http https httpsss"
pattern = re.compile(r'https{0,1}')
content = re.findall(pattern,str1)
1
content: ['http', 'https']

这样匹配的就是https或者http啦,当然{}里面也可以只有一个数字,那表示匹配前一个字符固定次数。

第五种:以上各种规则可以自由组合,形成功能强大的正则表达式。

1
2
3
4
import re
str1 = "hello,everyone,I am HelloHaibo,thank u for watching my blog"
pattern = re.compile(r'[Hh]ello')
content = re.findall(pattern,str1)
1
1
content: ['hello', 'Hello']

这个规则只匹配Hello或者hello[ ]虽然表示一个集合,但是也是匹配单个字符的。

1
2
3
4
import re
str1 = "<h1>www.baidu.com</h1><h2>www.imooc.com</h2><span>tttt</span>"
pattern = re.compile(r'<h[\d]>www\.[a-zA-Z]+\.com</h[\d]>')
content = re.findall(pattern,str1)
1
content: ['<h1>www.baidu.com</h1>', '<h2>www.imooc.com</h2>']

我们来分析一下:外围的<h[\d]></h[\d]>表示匹配<h1></h1>或者h2h3h4这样的标签;www\.表示匹配www.那为什么要加一个\呢,因为 . 在正则表达式中已经有特殊意义了,如果你直接写www.他会匹配www后面跟一个任意字符,所以我们需要一个转义符号,来说明我们就想匹配 . 本身;[a-zA-Z]+要匹配a-zA-Z这些字符一次或者任意次;\.com表示匹配.com这个字符串,当然实际中要考虑网址的多样性,后缀的多样性等等。

4、断言匹配(这个里面的核心思想是判断):

(?<=...)(?=...)两个分别称为后向匹配和前向匹配,它们判断是否成立,但是不参与匹配输出。

1
2
3
4
import re
str1 = "<h1>www.baidu.com</h1><h2>www.imooc.com</h2><span>tttt</span>"
pattern = re.compile(r'(?<=<h[\d]>)www\.[\w]+\.com(?=</h[\d]>)')
content = re.findall(pattern,str1)
1
content: ['www.baidu.com', 'www.imooc.com']

可以看到我把之前的<h[\d]></h[\d]>修改为(?<=<h[\d]>)(?=</h[\d]>),说明我要判断我要匹配的字符串开头是不是以<h1><h2><h3>….这样的标签开头,以</h1></h2></h3>…这样的标签结束,但是输出结果可以看出,并没有标签本身,只是把标签中间的内容输出,这在我们分析网页内容时候至关重要。

推荐:

《正则表达式必知必会(修正版)》