玩命加载中...

Python中的正则表达式

4个小节,预计用时20分钟

正则表达(Regular Expression,或简称RegEx)是编程语言中用来搜索文本中格式匹配的重要手段。比如说判断一个字符串是否包含合法的Email地址、找到文本中电话号码形式的字符出现的位置等等。

本教程将教会大家如何在Python中使用正则表达。

本教程基于Python 3.7

原创者:我小宋 | 修改校对:SofaSofa TeamM |


0. 准备

Python3中有自带的正则表达模块re,和其他模块一样,我们只需要import即可加载。

import re

下面的小例子,就是查找字符串中所有的in。通常我们在正则表达的格式前面加上r,比如下面的r"in"

string = "Taiwan is a province in China."
x = re.findall(r"in", string)
print(x)
['in', 'in', 'in']

1. 入门正则表达式

正则表达式本身也是用字符串表示,通常在引号前加上r。我们首先了解如何用字符来描述字符。

\d表示一个数字;

\w表示一个数字、一个字母或者一个下划线;

\s表示一个空格;

?表示任意0个或者一个字符;

.表示任意一个字符;

*表示任意一个字符串,甚至可以是空字符串;

+表示任意一个非空的字符串;

[]表示一个集合。

下面的例子中r"i\w\w"表示一个长度为3的字符串,第一个字符为i,第二三个字符是一个字母或者数字或者下划线。

所以我们得到的结果是inting

string = "I'm interested in buying the new BMW i3 car."
x = re.findall(r"i\w\w", string)
print(x)
['int', 'ing']

r"i\d"表示一个长度为2的字符,第一个字符为i,第二个字符是数字。

string = "I'm interested in buying the new BMW i3 car."
x = re.findall(r"i\d", string)
print(x)
['i3']

r"\w*i\w*"表示包含字母i的子字符串。

string = "I'm interested in buying the new BMW i3 car."
x = re.findall(r"\w*i\w*", string)
print(x)
['interested', 'in', 'buying', 'i3']

r"\w*[abc]\w*"表示包含字母a或者b或者c的子字符串。

string = "I'm interested in buying the new BMW i3 car."
x = re.findall(r"\w*[abc]\w*", string)
print(x)
['buying', 'car']

2. [ ]集合的使用

上一个例子我们看到了集合符号[ ]的一个例子。其实集合还有更丰富的用法,例如:

[125]表示1或者2或者5

[3-7]表示37的一个数字,也就是34567

[0-9+]表示09的一个数字或者+

[a-z]表示az的一个小写字母;

[a-zA-Z]表示az的或者AZ的一个大写字母;

[^xyz]表示除了xyz以外的任意一个字符;

[]{n}表示一个长度为n的子字符串,每个字符都来自集合;

[]{n,m}表示一个长度大于等于n小于等于m的子字符串,每个字符都来自集合。

r"2[0-9]{3}"表示以2开头的所有的四位数。下面的例子中,我们提取了句子中所有的年份。

string = "克洛泽参加的4届世界杯中,他一共打入16球,其中2002世界杯5球,2006德国世界杯5球,2010南非世界杯4球,2014巴西世界杯2球。"
x = re.findall(r"2[0-9]{3}", string)
print(x)
['2002', '2006', '2010', '2014']

3. re中的常见方法

re中的常见用法有re.searchre.matchre.findallre.splitre.sub

3.1 re.search

re.search(pattern, string)是搜索string中符合pattern的第一个字符串,返回一个SRE_Match对象。下面的例子中,我们搜索句子中第一个的年份;如果没有找到,则返回None。

string = "克洛泽参加的4届世界杯中,他一共打入16球,其中2002世界杯5球,2006德国世界杯5球,2010南非世界杯4球,2014巴西世界杯2球。"
x = re.search(r"2[0-9]{3}", string)
print('第一个年份:', x.group())
print('在string的范围:', x.span())
print('开头的位置:', x.start())
print('结束的位置(不包含):', x.end())
第一个年份: 2002
string的范围: (24, 28)
开头的位置: 24
结束的位置(不包含): 28

3.2 re.match

re.match(pattern, string)是对stringpattern进行匹配,返回一个SRE_Match对象,如果匹配失败则返回None。matchsearch的特殊情况,match必须从string的第一个字符开始匹配,要求更严格。

string = "克洛泽参加的4届世界杯中,他一共打入16球,其中2002世界杯5球,2006德国世界杯5球,2010南非世界杯4球,2014巴西世界杯2球。"

x = re.search(r"2[0-9]{3}", string)
if x: 
    print('re.search成功')
else:
    print('re.search失败')

x = re.match(r"2[0-9]{3}", string)
if x: 
    print('re.match成功')
else:
    print('re.match失败')
re.search成功
re.match失败

3.3 re.findall

re.findall(pattern, string)是从string找到所有符合pattern的子字符串,返回一个list,如果没有找到则返回一个空的list。

string = "克洛泽参加的4届世界杯中,他一共打入16球,其中2002世界杯5球,2006德国世界杯5球,2010南非世界杯4球,2014巴西世界杯2球。"
x = re.findall(r"2[0-9]{3}", string)
print(x)
['2002', '2006', '2010', '2014']

3.4 re.split

re.split(pattern, string)是从string找到所有符合pattern的子字符串,并以这些子字符串为切割点,对原字符串进行分隔,返回得到一个list,每个元素是被分割的子字符串。

如果没有找到则返回一个只包含string的list。

string = "克洛泽参加的4届世界杯中,他一共打入16球,其中2002世界杯5球,2006德国世界杯5球,2010南非世界杯4球,2014巴西世界杯2球。"
x = re.split(r"2[0-9]{3}", string)
print(x)
['克洛泽参加的4届世界杯中,他一共打入16球,其中', '世界杯5球,', '德国世界杯5球,', '南非世界杯4球,', '巴西世界杯2球。']

3.5 re.sub

re.split(pattern, replace, string)是查找替换的功能,从string找到所有符合pattern的子字符串,并替换成replace

string = "克洛泽参加的4届世界杯中,他一共打入16球,其中2002世界杯5球,2006德国世界杯5球,2010南非世界杯4球,2014巴西世界杯2球。"
x = re.sub(r"2[0-9]{3}", "某某年", string)
print(x)
克洛泽参加的4届世界杯中,他一共打入16球,其中某某年世界杯5球,某某年德国世界杯5球,某某年南非世界杯4球,某某年巴西世界杯2球。

4. 练习:利用Python正则表达判断合法Email地址

def IsValidEmail(email):
    pattern = r"[a-zA-Z0-9_+\.-]+@\w+\.\w+"
    if not re.match(pattern, email):
        return False
    return True

email1 = 'submit@sofasofa.io'
print('Is %s valid? %s\n'%(email1, IsValidEmail(email1)))

email2 = 'a?b@gmail'
print('Is %s valid? %s\n'%(email2, IsValidEmail(email2)))

email3 = '123@456@qq.com'
print('Is %s valid? %s\n'%(email3, IsValidEmail(email3)))
Is submit@sofasofa.io valid? True

Is a?b@gmail valid? False

Is 123@456@qq.com valid? False