有人在碰到问题时,就想:“我知道,我可以用正则表达式。”现在,他就有了两个问题。


正则表达式

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。为高级的文本模式匹配、抽取、与/或文本形式的搜索和替换提供了基础。

re 模块使 Python 语言拥有全部的正则表达式功能。

  • 搜索,在字符串任意部分中搜索匹配的模式。search()
  • 匹配,是判断一个字符串能否从起始处全部或者部分地匹配某个模式。match()

compile函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。
该对象拥有一系列方法用于正则表达式匹配和替换。

re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。

特殊符号和字符

常见正则表达式符号和特殊字符
表示法 描述
literal 匹配文本字符串的字面值literal
re1|re2 匹配正则表达式 re1 或者 re2(管道符号)
. 匹配任何字符(除了\n之外)
^ 匹配字符串起始部分
$ 匹配字符串终止部分
* 匹配 0 次或者多次前面出现的正则表达式
+ 匹配 1 次或者多次前面出现的正则表达式
? 匹配 0 次或者 1 次前面出现的正则表达式,非贪婪
{N} 匹配 N 次前面出现的正则表达式
{M,N} 匹配 M~N 次前面出现的正则表达式
[] 匹配来自字符集的任意单一字符
[…x−y…] 匹配 x ~ y 范围中的任意单一字符
[^] 不匹配此字符集中出现的任何一个字符,包括某一范围的字符
() 匹配封闭的正则表达式,然后另存为子组
\d 匹配任何十进制数字,与[0-9]一致(\D与之相反)
\b 匹配任何单词边界,指单词和空格间的位置(\B与之相反)
\w 匹配任何字母数字字符,与[A-Za-z0-9_]相同(\W与之相反)
\s 匹配任何空格字符,与[\n\t\r\v\f]相同(\S与之相反)
\N 匹配已保存的子组 N(参见上面的())
\c 逐字匹配任何特殊字符c(即仅按照字面意义匹配,不匹配特殊含义)
\A(\Z) 匹配字符串的起始(结束)(另见上面介绍的^$
(?iLmsux) 嵌入一个或者多个特殊“标记”参数(或者通过函数/方法)
(?:) 表示一个匹配不用保存的分组
(?P<name>…) 像一个仅由name标识而不是数字 ID 标识的正则分组匹配
(?P=name) 在同一字符串中匹配由(?P<name)分组的之前文本
(?#) 表示注释,所有内容都被忽略
(?=) 匹配条件是如果…出现在之后的位置,而不使用输入字符串;称作正向前视断言
(?!) 匹配条件是如果…不出现在之后的位置,而不使用输入字符串;称作负向前视断言
(?<=) 匹配条件是如果…出现在之前的位置,而不使用输入字符串;称作正向后视断言
(?<!) 匹配条件是如果…不出现在之前的位置,而不使用输入字符串;称作负向后视断言

常用正则表达式

用处
用户名 /^\[a-z0-9_-\]{3,16}$/
密码 /^\[a-z0-9_-\]{6,18}$/
十六进制值 /^#?(\[a-f0-9\]{6}\|\[a-f0-9\]{3})$/
电子邮箱 /^(\[a-z0-9_\.-]+)@(\[\da-z\.-\]+)\.(\[a-z\.\]{2,6})\$/
/^\[a-z\d\]+(\.\[a-z\d\]+)*@(\[\da-z](-\[\da-z\])?)+(\.{1,2}\[a-z\]+)+$/
URL /^(https?:\/\/)?(\[\da-z\.-\]+)\.(\[a-z\.\]{2,6})([\/\w \.-]*)*\/?$/
IP 地址 /((2\[0-4\]\d\|25\[0-5\]\|[01]?\d\d?)\.){3}(2[0-4]\d\|25[0-5]\|[01]?\d\d?)/ <br />/^(?:(?:25[0-5]\|2\[0-4][0-9]\|[01]?\[0-9][0-9]?)\.){3}(?:25[0-5]\|2\[0-4][0-9]\|[01]?\[0-9][0-9]?)$/
HTML 标签 /\^<([a-z]+)(\[^<]+)\*(?:>(.*)<\/\1>\|\s+\/>)$/
删除代码\注释 (?<!http:\|\S)//.*$
Unicode编码中的汉字范围 /^[\u2E80-\u9FFF]+$/

re.search 扫描整个字符串并返回第一个成功的匹配。

1
2
3
print(re.search('www', 'www.runoob.com').span())
print(re.search('com', 'www.runoob.com').span())
print(re.search('com', 'www.runoob.com.com').span())
1
2
3
(0, 3)
(11, 14)
(11, 14)

re.match()

re.match尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

1
2
3
import re
print(re.match('www', 'www.runoob.com').span()) # 在起始位置匹配
print(re.match('com', 'www.runoob.com')) # 不在起始位置匹配
(0, 3)
None

group()groups()

group(num)groups() 匹配对象函数来获取匹配表达式。

group(num=0)匹配的整个表达式的字符串,group()可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。

groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

1
2
3
4
5
6
7
8
9
10
11
line = "Cats are smarter than dogs"
# .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)

if matchObj:
print ("matchObj.group() : ", matchObj.group())
print ("matchObj.group(1) : ", matchObj.group(1))
print ("matchObj.group(2) : ", matchObj.group(2))
print ("matchObj.groups() :",matchObj.groups())
else:
print ("No match!!")
matchObj.group() :  Cats are smarter than dogs
matchObj.group(1) :  Cats
matchObj.group(2) :  smarter
matchObj.groups() : ('Cats', 'smarter')

re.sub()

re.sub用于替换字符串中的匹配项。

re.sub(pattern, repl, string, count=0, flags=0)

  • pattern : 正则中的模式字符串。
  • repl : 替换的字符串,也可为一个函数。
  • string : 要被查找替换的原始字符串。
  • count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
  • flags : 编译时用的匹配模式,数字形式。
1
2
3
4
5
6
7
8
9
phone = "2004-959-559 # 这是一个电话号码"

# 删除注释
num = re.sub(r'#.*$', "", phone)
print ("电话号码 : ", num) # 电话号码 : 2004-959-559

# 移除非数字的内容
num = re.sub(r'\D', "", phone)
print ("电话号码 : ", num) # 电话号码 : 2004959559
1
2
3
4
5
6
7
# 将匹配的数字乘于 2
def double(matched):
value = int(matched.group('value'))
return str(value * 2)

s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s)) # A46G8HFD1134

re.compile

compile函数用于编译正则表达式,生成一个正则表达式(Pattern)对象,供match()search()这两个函数使用。
re.compile(pattern[, flags])

  • pattern : 一个字符串形式的正则表达式
  • flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
    • re.I 忽略大小写
    • re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
    • re.M 多行模式
    • re.S 即为’ . ‘并且包括换行符在内的任意字符(’ . '不包括换行符)
    • re.U表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
    • re.X 为了增加可读性,忽略空格和’ # '后面的注释
1
2
3
4
5
6
7
pattern = re.compile(r'\d+')                    # 用于匹配至少一个数字
pattern = re.compile(r'\d+') # 用于匹配至少一个数字
m = pattern.match('one12twothree34four') # 查找头部,没有匹配
print("从头部开始匹配",m) # 从头部开始匹配 None
m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
print(m) # <re.Match object; span=(3, 5), match='12'> # 返回一个 Match 对象
print(m.group()) # 12

re.findall()

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

re.findall(string[, pos[, endpos]])

  • string 待匹配的字符串。
  • pos 可选参数,指定字符串的起始位置,默认为 0。
  • endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
1
2
3
4
5
6
pattern = re.compile(r'\d+')   # 查找数字
result1 = pattern.findall('runoob 123 google 456')
result2 = pattern.findall('run88oob123google456', 0, 10)

print(result1) # ['123', '456']
print(result2) # ['88', '12']

re.finditer()

findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

1
2
3
it = re.finditer(r"\d+","12a32bc43jf3") 
for match in it:
print (match.group() ) ## 12 32 43 3

re.split

split方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:

re.split(pattern, string[, maxsplit=0, flags=0])

  • pattern匹配的正则表达式
  • string要匹配的字符串。
  • maxsplit分隔次数,maxsplit=1分隔一次,默认为 0,不限制次数。
  • flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
1
re.split('\W+', 'runoob, runoob, runoob.')  # ['runoob', 'runoob', 'runoob', '']

当匹配成功时返回一个 Match 对象,其中:

  • group(\[group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() group(0)
  • start(\[group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
  • end(\[group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
  • span(\[group])方法返回(start(group), end(group))