Regular Expression

正则表达式就是描述字符串排列的一套规则。

基础知识

原子

原子是正则表达式中最基本的组成单位,每个正则表达式中至少要包含一个原子,常见的原子有以下几类:

  1. 普通字符
  2. 非打印字符
  3. 通用字符
  4. 原子表

普通字符

可以使用一些普通的字符,比如数字、大小写字母、下划线等都可以作为原子使用。

1
2
3
4
5
6
7
import re

pattern = "yue"
string = "http://yum.iqianyue.com"
result = re.search(pattern, string)
print(result)
# <re.Match object; span=(16, 19), match='yue'>

非打印字符

所谓的非打印字符,指的是一些在字符串中用于格式控制的符号,比如换行符等。
Pgf3o6.png

1
2
3
4
5
6
7
8
9
10
11
12
13
import re

pattern = "\n"
string1 = '''http://yum.iqianyue.com
http://baidu.com'''
result1 = re.search(pattern, string1)
print(result1)
# <re.Match object; span=(23, 24), match='\n'>

string2 = "http://yum.iqianyue.comhttp://baidu.com"
result2 = re.search(pattern, string2)
print(result2)
# None

通用字符

所谓的通用字符,即一个原子可以匹配一类字符。
PgfBwt.png

1
2
3
4
5
6
7
import re

pattern = "\w\dpython\w"
string = "abcdfphp345pythony_py"
result = re.search(pattern, string)
print(result)
# <re.Match object; span=(9, 18), match='45pythony'>

原子表

使用原子表,可以定义一组地位平等的原子,然后匹配的时候会取该原子表中的任意一个原子进行匹配,在Python中,原子表由[]表示。类似的,[^]代表的是除了中括号里面的原子均可以匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import re

string = "abcdfphp345pythony_py"
pattern1 = "\w\dpython[xyz]\w"
result1 = re.search(pattern1, string)
print(result1)
# <re.Match object; span=(9, 19), match='45pythony_'>

pattern2 = "\w\dpython[^xyz]\w"
result2 = re.search(pattern2, string)
print(result2)
# None

pattern3 = "\w\dpython[xyz]\W"
result3 = re.search(pattern3, string)
print(result3)
# None

元字符

所谓的元字符,就是正则表达式中具有一些特殊含义的字符。具体来说,元字符可以分为:任意匹配元字符、边界限制元字符、限定符、模式选择符、模式单元等。
PgfL6J.png

任意匹配元字符

可以使用”.”匹配一个除换行符以外的任意字符。

1
2
3
4
5
6
7
import re

pattern = ".python..."
string = "abcdfphp345pythony_py"
result = re.search(pattern, string)
print(result)
# <re.Match object; span=(10, 20), match='5pythony_p'>

边界限制元字符

可以使用”^”匹配字符串的开始,使用”$”匹配字符串的结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import re

string = "abcdfphp345pythony_py"
pattern1 = "^abd"
result1 = re.search(pattern1, string)
print(result1)
# None

pattern2 = "^abc"
result2 = re.search(pattern2, string)
print(result2)
# <re.Match object; span=(0, 3), match='abc'>

pattern3 = "py$"
result3 = re.search(pattern3, string)
print(result3)
# <re.Match object; span=(19, 21), match='py'>

pattern4 = "ay$"
result4 = re.search(pattern4, string)
print(result4)
# None

限定符

常见的限定符包括*、?、+、{n}、{n,}、{n, m}。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import re

string = "abcdddfphp345pythony_py"
pattern1 = "py.*n"
result1 = re.search(pattern1, string)
print(result1)
# <re.Match object; span=(13, 19), match='python'>

pattern2 = "cd{2}"
result2 = re.search(pattern2, string)
print(result2)
# <re.Match object; span=(2, 5), match='cdd'>

pattern3 = "cd{3}"
result3 = re.search(pattern3, string)
print(result3)
# <re.Match object; span=(2, 6), match='cddd'>

pattern4 = "cd{2,}"
result4 = re.search(pattern4, string)
print(result4)
# <re.Match object; span=(2, 6), match='cddd'>

模式选择符

使用模式选择符,可以设置多个模式,匹配时,可以从中选择任意一个模式匹配。

1
2
3
4
5
6
7
import re

pattern = "python|php"
string = "abcdfphp345pythony_py"
result = re.search(pattern, string)
print(result)
# <re.Match object; span=(5, 8), match='php'>

模式单元

可以使用”()”将一些原子组合成一个大原子使用,小括号括起来的部分会被当做一个整体去使用。

1
2
3
4
5
6
7
8
9
10
11
12
import re

string = "abcdcdcdcdfphp345pythony_py"
pattern1 = "(cd){1,}"
result1 = re.search(pattern1, string)
print(result1)
# <re.Match object; span=(2, 10), match='cdcdcdcd'>

pattern2 = "cd{1,}"
result2 = re.search(pattern2, string)
print(result2)
# <re.Match object; span=(2, 4), match='cd'>

模式修正

所谓模式修正符,即可以在不改变正则表达式的情况下,通过模式修正符改变正则表达式的含义,从而实现一些匹配结果的调整等功能。
Pgh1Xj.png

1
2
3
4
5
6
7
8
9
10
11
import re

string = "abcdfphp345Pythony_py"
pattern = "python"
result1 = re.search(pattern, string)
print(result1)
# None

result2 = re.search(pattern, string, re.I)
print(result2)
# <re.Match object; span=(11, 17), match='Python'>

贪婪模式与懒惰模式

在某些字符间匹配任意字符,贪婪模式的核心点就是尽可能多地匹配,而懒惰模式的核心点就是尽可能少地匹配。

1
2
3
4
5
6
7
8
9
10
11
12
import re

string = "abcdfphp345pythony_py"
pattern1 = "p.*y" #贪婪模式
result1 = re.search(pattern1, string)
print(result1)
# <re.Match object; span=(5, 21), match='php345pythony_py'>

pattern2 = "p.*?y" #懒惰模式
result2 = re.search(pattern2, string)
print(result2)
# <re.Match object; span=(5, 13), match='php345py'>

常见函数

re.match()函数

如果想要从源字符串的起始位置匹配一个模式,可以使用re.match()函数,使用格式是:
re.match(pattern, string, flag)
第一个参数代表对应的正确表达式,第二个参数代表对应的源字符,第三个参数是可选参数,代表对应的标志位,可以放模式修正符等信息。

1
2
3
4
5
6
7
8
9
10
11
import re

string = "apythonhellomypythonhispythonourpythonend"
pattern = ".python."
result1 = re.match(pattern, string)
print(result1)
# <re.Match object; span=(0, 8), match='apythonh'>

result2 = re.match(pattern, string).span()
print(result2)
# (0, 8)

re.search()函数

使用该函数进行匹配,会扫描整个字符串并进行对应的匹配。

1
2
3
4
5
6
7
8
9
10
11
import re

string = "hellomypythonhispythonourpythonend"
pattern = ".python."
result1 = re.match(pattern, string)
print(result1)
# None

result2 = re.search(pattern, string)
print(result2)
# <re.Match object; span=(6, 14), match='ypythonh'>

全局匹配函数

将符合模式的内容全部都匹配出来。思路如下:

  1. 使用re.compile()对正则表达式进行预编译。
  2. 编译后,使用findall()根据正则表达式从源字符串中将匹配的结果全部找出。
1
2
3
4
5
6
7
import re

string = "hellomypythonhispythonourpythonend"
pattern = re.compile(".python.") #预编译
result = pattern.findall(string) #找出符合模式的所有结果
print(result)
# ['ypythonh', 'spythono', 'rpythone']

re.sub()函数

如果想根据正则表达式来实现替换某些字符串的功能,可以使用re.sub()韩式实现。
re.sub(pattern, rep, string, max)
其中,第一个参数为对应的正则表达式,第二个参数为要替换成的字符串,第三个参数为源字符串,第四个参数为可选项,代表最多替换的次数,如果忽略不写,则会将符合模式的结果全部替换。

1
2
3
4
5
6
7
8
9
10
11
import re

string = "hellomypythonhispythonourpythonend"
pattern = re.compile(".python")
result1 = re.sub(pattern, "php", string) #全部替换
print(result1)
# hellomphphiphpouphpend

result2 = re.sub(pattern, "php", string, 2) #最多替换两次
print(result2)
# hellomphphiphpourpythonend

常见实例解析

匹配.com或.cn后缀的URL网址

将一串字符串里面以.com或.cn为域名后缀的URL网址匹配出来,过滤掉其他的无关信息。

1
2
3
4
5
6
7
import re

pattern = "[a-zA-Z]+://[^\s]*[.com|.cn]"
string = "<a href='http://www.baidu.com'>百度首页</a>"
result = re.search(pattern, string)
print(result)
# <re.Match object; span=(9, 29), match='http://www.baidu.com'>

匹配电话号码

将一串字符串里面出现的电话号码信息提取出来,过滤掉其他无关信息。

1
2
3
4
5
6
7
import re

pattern = "\d{4}-\d{7}|\d{3}-\d{8}"
string = "021-6728263653682382265236"
result = re.search(pattern, string)
print(result)
# <re.Match object; span=(0, 12), match='021-67282636'>

匹配电子邮件地址

将一串字符串里面出现的电子邮件信息提取出来,过滤掉其他无关信息。

1
2
3
4
5
6
7
import re

pattern = "\w+([.+-]\w+)*@\w+([.-]\w+)*\.\w+([.-]\w+)*"
string = "<a href='http://www.baidu.com'>百度首页</a><br><a href='mailto:c-e+o@iqi-anyue.com.cn'>电子邮件地址</a>"
result = re.search(pattern, string)
print(result)
# <re.Match object; span=(59, 81), match='c-e+o@iqi-anyue.com.cn'>