Python正则表达式
正则表达式(Regular Expression)是一种文本模式,包括普通字符和特殊字符(元字符)。正则表达式使用单个字符串来描述、匹配一系列匹配某个语法规则的字符串。
一、基本语法
1.1 普通字符
正则表达式模式 | 匹配的字符串 |
---|---|
foo | foo |
Python | Python |
abc123 | abc123 |
1.2 非打印字符
1.2.1 非打印字符正则表达式
字符 | 描述 |
---|---|
\cx | 匹配由x 指明的控制符。例如\cM 匹配一个Ctrl+M 组合键或Enter |
\f | 匹配一个换页符。等价于\x0c 和cL |
\n | 匹配一个换行符。等价于x0a 和cJ |
\r | 匹配一个回车符。等价于\x0d 和\cM |
\s | 匹配任何空白字符,包括空格、制表符、换页符等。等价于[\f\n\r\t\v ] |
\S | 匹配任何非空白字符。等价于[^\f\n\r\t\v ] |
\t | 匹配一个制表符。等价于\x09 和\cI |
\v | 匹配一个垂直制表符。等价于\x0b 和\cK |
1.3 特殊字符
1.3.1 特殊字符正则表达式
特殊字符 | 描述 |
---|---|
$ | 匹配输入字符串的结尾位置 |
() | 标记一个表达式的开始和结束位置 |
* | 匹配前面的子表达式零次或者多次 |
+ | 匹配前面子表达式一次或多次 |
. | 匹配除了换行符\n 之外的任何单字符 |
[ | 标记一个中括号表达式的开始 |
? | 匹配前面的子表达式零次或者一次 |
\ | 引用或者转义 |
^ | 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时表示不接受该字符集合 |
{ | 标记限定符表达式的开始 |
| | 指明两项之间的一个选择。“或”的意思 |
注:上述的字符需要匹配对应字符是,应该在前面加上\
表示转义。
1.3.2 匹配任意单个字符的演示信息
正则表达式模式 | 匹配的字符串 |
---|---|
f.o | 匹配在字母f 和o 之间的任意一个字符,例如fao、f9o、f#o等 |
.. | 任意两个字符 |
.end | 匹配在字符串end 之前的任意一个字符串 |
1.3.3 特殊符号\b
和\B
匹配字符边界
正则表达式模式 | 匹配的字符串 |
---|---|
the | 任何包含the 的字符串 |
\bthe | 任何以the 开头的字符串 |
\bthe\b | 仅仅匹配单词the |
\Bthe | 任何包含但并不以the 作为开头的字符串 |
1.3.4 创建字符集
正则表达式模式 | 匹配的字符串 |
---|---|
b[aeiu]t | bat 、bet 、bit 、but |
[cr][23][dp][o2] | 一个包含四个字符的字符串。字符1:c 或r 、字符二:2 或3 … |
1.3.5 使用闭包操作符实现存在性和频数匹配
正则表达式模式 | 匹配的字符串 |
---|---|
[dn]ot? | do 、no 、dot 、not |
0?[1-9] | 01 、02 ……09 或1 、2 ……9 |
[0-9]{15,16} | 匹配十五或者16个数字(例如信用卡号码) |
</?[^>]+> | 匹配全部有效或者无效的HTML 标签 |
[KQRBNP][a-h][1-8]-[a-h][1-8] | 表示国际象棋上棋盘移动 |
1.3.6 表示字符集的特殊字符
\d
:[0-9]
匹配任何十进制数字 \w
:[A-Za-z0-9]
全部字母和数字的字符集
正则表达式模式 | 匹配的字符集 |
---|---|
\w+-\d+ | |
[A-Za-z]\w* | 几乎等价于Python 中的有效标识符 |
\d{3,4}-\d{7,8} | 电话号码的格式,前面是区号前缀,例如010-12345678 |
\w+@\w+.com | 以XXX@YYY.com 格式表示简单的电子邮件地址 |
1.4 限定符
1.4.1 正则表达式中的限定符信息
字符 | 描述 |
---|---|
* | 匹配前面的子表达式零次或多次。例如zo* 能匹配z 以及zoo 。* 等价于{0,} |
+ | 匹配前面的子表达式一次或多次。例如zo+ 能匹配zo 以及zoo ,但不能匹配z 。+ 等价于{1,} |
? | 匹配前面的子表达式零次或者一次。例如do(es)? 可以匹配do 或does 中的do 。? 等价于{0,1} |
{n} | n 是一个非负整数。匹配确定的n 次。例如0{2} 可以匹配food 中的oo |
{n,} | n 是一个非负整数。至少匹配n 次 |
{n,m} | m 和n 均为非负整数。其中n <=m ,至少匹配n 次,至多匹配m 次 |
1.5 定位符
1.5.1 常用的正则表达式定位符
字符 | 描述 |
---|---|
^ | 匹配输入字符串开始的位置 |
$ | 匹配输入字符串结尾的位置 |
b | 匹配一个字边界,即字与空格间的位置 |
B | 非字边界匹配 |
1.6 限定范围与否定
正则表达式模式 | 匹配的字符串 |
---|---|
z.[0-9] | 字母z 后面跟着任何一个字符,然后跟着一个数字 |
[r-u][env-y][us] | 字母r 、s 、t 或者u 后面跟着e 、n 、v 、w 、x 、或者y ,然后跟着u 或者s |
[^aeiou] | 一个非元音字符 |
[^\t\n] | 不匹配制表符和换行符 |
["-a] | 在一个ASCII 码系统中,所有字符都位于" 和a 之间,即34~97 |
1.7 运算符优先级
转义符\
>圆括号和方括号>限定符>定位点和序列>替换符|
1.8 案例
二、re模块
2.1 re模块库函数介绍
2.1.1 re模块中常用的内置库函数和方法
2.1.2 re模块中常用的属性信息
属性 | 说明 |
---|---|
re.I 、re.IGNORECASE | 不区分大小写的匹配 |
re.L 、re.LOCALE | 根据所使用的本地语言环境通过\w 、\W 、\b 、\B 、\s 、\S 实现匹配 |
re.M 、re.MULTILINE | ^ 和$ 分别匹配目标字符串中行的起始和结尾,为不是严格匹配整个字符串本身的开始和结尾 |
re.S 、re.DOTALL | . 匹配全部字符 |
re.X 、re.VERBOSE | 通过反斜杠转义后,所有空格加上# (以及在该行中所有后续文字)的内容都被忽略 |
2.2 函数compile()
2.2.1 语法格式
compile()
用于编译正则表达式。并返回一个编译的正则表达式对象regex
。编译后的正则表达式可以重复使用,减少正则表达式的解析和验证,提高了效率。
compile(source, filename, mode[, flags[, dont_inherit]])
source
:字符串或者AST(Abstract Syntax Tree)对象filename
:代码文件名称,如果不是从文件读取代码,则传递一些可辨认的值mode
:指定编译代码的种类,可以指定exec
、eval
和single
参数 | 含义 |
---|---|
re.I 、re.IGNORECASE | 忽略大小写 |
re.L 、re.LOCALE | 根据所使用的本地设置更改\w 、\W 、\b 、\B 、\s 、\S 的匹配内容 |
re.M 、re.MULTILINE | 多行匹配模式 |
re.S 、re.DOTALL | 使. 元字符也匹配字符串 |
re.U 、re.Unicode | 匹配Unicode 字符 |
re.A 、re.ASCII | 匹配ASCII 字符 |
re.X 、re.VERBOSE | 忽略pattern 中的空格,并且可以使用# 注释 |
2.2.2 案例
#正则表达式未编译
import re
p = '[Jj]ava'
text = 'I like Java and java'
match_list = re.findall(p, text)
print(match_list)
#正则表达式编译
import re
p = '[Jj]ava'
text = 'I like Java and java'
regex = re.compile(p)
match_list = regex.findall(text)
print(match_list)
#re.DOTALL
import re
p = '.+'
regex = re.compile(p)
m = regex.search('Hello\nWorld.')
print(m)
#<re.Match object; span=(0, 5), match='Hello'>
regex = re.compile(p, re.DOTALL)
m = regex.search('Hello\nWorld.')
print(m)
#<re.Match object; span=(0, 12), match='Hello\nWorld.'>
#re.IGNORECASE
import re
p = '(java).*(python)'
regex = re.compile(p)
m = regex.search('I like Java and Python')
print(m)
#None
regex = re.compile(p, re.I)
m = regex.search('I like Java and Python')
print(m)
#<re.Match object; span=(7, 22), match='Java and Python'>
#re.Unicode
import re
text = '你们好Hello'
p = '\w+'
regex = re.compile(p, re.U)
m = regex.search(text)
print(m)
#<re.Match object; span=(0, 8), match='你们好Hello'>
regex = re.compile(p, re.A)
m = regex.search(text)
print(m)
#<re.Match object; span=(3, 8), match='Hello'>
#re.MULTILINE
import re
p = '^World'
regex = re.compile(p)
m = regex.search('Hello\nWorld.')
print(m)
#None
regex = re.compile(p, re.M)
m = regex.search('Hello\nWorld.')
print(m)
#<re.Match object; span=(6, 11), match='World'>
#re.VERBOSE
import re
p = '''(java) #匹配java字符串
.* #匹配任意字符零个或者多个
(python) #匹配python字符串
'''
regex = re.compile(p, re.I|re.VERBOSE) #使用多种模式时,用|隔开
m = regex.search('I like Java and Python')
print(m)
#<re.Match object; span=(7, 22), match='Java and Python'>
2.3 函数match()
match()
在输入字符串开始处查找匹配内容,如果找到一个,则返回match
对象,如果没有找到,返回None
,多为验证的时候用。
2.3.1 语法格式
re.match(pattern, string, flags = 0)
pattern
:匹配的正则表达式string
:要匹配的字符串flags
:标志位,用于控制正则表达式的匹配方式
2.3.2 案例
import re
re.match(r'dog', 'dog cat dog')
match = re.match(r'dog', 'dog cat dog')
match.group(0)
#'dog'
2.4 函数search()
search()
在输入字符串中查找,返回第一个匹配内容。如果找到一个,则返回match
对象,如果没有找到就返回None
。
2.4.1 语法格式
re.search(pattern, string, flags = 0)
- 参数意义同上
import re
p = '\w+@163\.com'
text = 'My Email is abc@163.com'
m1 = re.search(p, text)
print(m1) #匹配
m2 = re.match(p, text)
print(m2) #不匹配
email = 'abc@163.com'
m3 = re.match(p, email)
print(m3) #匹配
2.4.2 案例
import re
s = 'i love python very much'
pat = 'python'
r = re.search(pat,s)
print(r.span()) #span():匹配字符的范围
#(7,13)
2.5 函数findall()
findall()
在输入字符串中查找所有匹配内容。如果匹配成功,则返回match
列表对象;如果匹配失败,则返回None
。
2.5.1 语法格式
re.findall(pattern, string, flags = 0)
- 参数意义同上
2.5.2 案例
import re
s = '一共20行代码运行时间13.59s'
pat = r'\d+' # +表示匹配数字(\d表示数字的通用字符)1次或多次
r = re.findall(pat,s)
print(r)
# ['20', '13', '59']
import re
s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'\s[a-zA-Z]+'
r = re.findall(pat,s)
print(r) #[' module', ' provides', ' regular', ' expression', ' matching', ' operations', ' similar', ' to', ' those', ' found', ' in', ' Perl']
2.6 函数finditer()
finditer()
在输入字符串中查找所有匹配内容。如果匹配成功,则返回容纳match
的可迭代对象,通过迭代对象每次可以返回一个match
对象;如果匹配失败,则返回None
。
import re
p = '[Jj]ava'
text = 'I like Java and java'
match_list = re.findall(p, text)
print(match_list)
# ['Java', 'java']
match_iter = re.finditer(p, text)
print(match_iter)
#<callable_iterator object at 0x012F0FD0>
for item in match_iter:
print(item)
#<re.Match object; span=(7, 11), match='Java'>
#<re.Match object; span=(16, 20), match='java'>
2.7 函数sub()
sub
函数用于替换匹配的字符串,返回值是替代之后的字符串。
2.7.1 语法格式
re.sub(pattern, repl, string, count = 0 flags = 0)
pattern
:匹配的正则表达式repl
:要替换的内容string
:进行内容替换的字符串count
:可选参数,最大替换次数flags
:标志位,用于控制正则表达式的匹配方式
2.7.2 案例
import re
p = '\d+'
text = 'AB12CD34EF'
replace_text = re.sub(p, '', text)
print(replace_text)
#ABCDEF
replace_text = re.sub(p, '', text, count = 1)
print(replace_text)
#ABCD34EF
三、正则表达式应用
3.1 懒惰量词与贪婪量词
量词可以细分为贪婪量词和懒惰量词,贪婪量词会尽可能多地匹配字符,懒惰量词会尽可能少地匹配字符。大部分计算机语言的正则表达式量词默认是贪婪的,要想使用懒惰量词,在量词后面加
?
即可。
import re
#使用贪婪量词
m = re.search(r'\d{5,8}', '87654321') #出现数字八次
print(m) #匹配字符'87654321'
#使用懒惰量词
m = re.search(r'\d{5,8}', '87654321')
print(m) #匹配字符'87654'
3.2 分组
3.2.1 使用分组
import re
p1 = '(121){2}'
p2 = '121{2}'
m1 = re.search(p1, '121121abcabc')
m2 = re.search(p2, '121121abcabc')
print(m1)
print(m2)
#<re.Match object; span=(0, 6), match='121121'>
#<re.Match object; span=(0, 4), match='1211'>
print(m1.group()) #返回匹配的字符串
#121121
print(m1.group(1)) #第一个分组的内容
#121
print(m1.groups()) #获得所有组的内容,返回一个元组
#('121',)
3.2.2 命名分组
组命名语法是在分组的左小括号后面添加
?P<分组名>
实现
###电话号码区号和号码分组
import re
p = '(?P<area_code>\d{3,4})-(?P<phone_code>\d{7,8})'
m = re.search(p, '010-87654321')
print(m.group(1)) #区号
print(m.group(2)) #号码
#010
#87654321
print(m.group('area_code')) #区号
print(m.group('phone_code')) #号码
#010
#87654321
3.2.3 反向引用分组
除了可以在程序代码中访问正则表达式匹配之后的分组内容,还可以在正则表达式内部引用之前的分组
import re
p1 = '<([\w]+)>.*</\1>' #反向引用
p2 = '<([\w]+)>.*</([\w]+)>'
m1 = re.search(p1, '<a>abc</b>')
print(m1)
m2 = re.search(p2, '<a>abc</b>')
print(m2)
#None
#<re.Match object; span=(0, 10), match='<a>abc</b>'>
3.2.4 非捕获分组
#捕获分组
import re
s = 'img1.jpg,img2.jpg,img3.bmp'
p = '\w+(\.jpg)'
m = re.findall(p, s)
print(m)
#['.jpg', '.jpg']
#非捕获分组
import re
s = 'img1.jpg,img2.jpg,img3.bmp'
p = '\w+(?:\.jpg)'
m = re.findall(p, s)
print(m)
#['img1.jpg', 'img2.jpg']
3.3 字符串分割
3.3.1 语法格式
字符串分割使用
split()
函数,该函数按照匹配的子字符串进行分割字符串,返回字符串列表对象。
re.split(pattern, string, maxsplit = 0, flags = 0)
pattern
:匹配的正则表达式string
:要匹配的字符串maxsplit
:最大分割次数flags
:标志位,用于控制正则表达式的匹配方式
3.3.2 案例
import re
p = '\d+'
text = 'AB12CD34EF'
clist = re.split(p, text)
print(clist)
# ['AB', 'CD', 'EF']
dlist = re.split(p, text, maxsplit = 1)
print(dlist)
# ['AB', 'CD34EF']