正则表达式
- 介绍:在实际开发中经常会有查找某些复杂规则的字符串的需求,比如邮箱、图片地址、手机号码等,这时候想要匹配或者查找某些规则的字符串就可以使用正则表达式了。
- 正则表达式是用于处理字符串的强大工具,其他编程语言中也有正则表达式的概念,区别只在于不同的编程语言支持的语法数量不同。
- 概念:正则表达式(或
RE
)是一种小型的、高度专业化的编程语言,正则表达式就是记录文本规则的代码,它内嵌在Python
中,并通过re
模块实现。 - 特点:
- 正则表达式的语法很令人头疼,可读性差;
- 正则表达式通用性很强,能够适用很多编程语言;
- 正则表达式拥有自己独特的语法以及一个独立的处理引擎(正则表达式模式被编译成一系列的字节码,然后由用
C
编写的匹配引擎执行),在提供了正则表达式的语言里,正则表达式的语法都是一样的。 - 正则表达式语言相对小型和受限(功能有限);
- 并非所有字符串处理都能用正则表达式完成。
反斜杠的麻烦
In [1]: "hello\nworld" # Out[1]: 'hello\nworld'
In [2]: r"hello\nworld" # Out[2]: 'hello\\nworld'
In [3]: a = "hello\nwordl"
In [4]: b = r"hello\nworld"
In [5]: print(a)
hello
wordl
In [6]: print(b)
hello\nworld
扩展:“\
”
- 用于取消所有的元字符(转译为普通符号),如:
- “
[]
”在正则中表示列举的字符集,如果仅仅想匹配“[]
”符号,可以使用“\[\]
”将其转译为普通符号。 - “
.
”在正则总表示除\n
以外的任意一个字符,如果仅仅想匹配“.
”符号,可以使用“\.
”将其转译为普通符号。
- 后面可以加不同的字符以表示不同特殊含义,如:
- 加
d
、D
、w
、W
等表示特殊的字符集,具体看后面的表; - 加数字,表示引用的分组编号,看下面的“匹配分组”;
- 加
n
、t
等表示换行、缩进等。
正则匹配的函数
RegexObject
实例有一些方法和属性,完整的列表可查询Python Library Reference
:
- 如果没有匹配成功的话,
match()
和search()
将返回None
; - 如果成功的话,就会返回一个
MatchObject
对象;
方法 | 作用 |
| 根据正则表达式从头开始匹配字符串数据 |
| 根据正则表达式从头到尾匹配字符串数据,匹配1次 |
| 找到 |
| 找到 |
| 按照 |
| 根据 |
| 根据 |
sub()
:正则替换字符串
rs = r'c..t'
re.sub(rs, 'python', 'csvt caat cvvt cccc')
-------------------------------------------
结果:'python python python cccc'
-
replace()
:字符串方法,替换字符串,会把正则表达式当成普通的字符串。
'csvt caat cvvt c..t cccc'.replace('c..t', 'python')
-------------------------------------------------------------
结果:'csvt caat cvvt python cccc' # replace()不认识正则表达式
subn()
替换字符串,并返回替换了几次
rs = r'c..t'
re.subn(rs, 'python', 'csvt caat cvvt cccc')
结果:('python python python cccc', 3)
MatchObject
实例方法
方法 | 作用 |
| 返回被 |
| 返回匹配开始的位置 |
| 返回匹配结束的位置 |
| 返回一个元组包含匹配(开始,结束)的位置 |
- 实际程序中,最常见的做法是将
MatchObject
保存在一个变量里,然后检查它是否为空。
p = re.compile(...)
m = p.match('string goes here')
if m:
# group()参数代表索引,从1开始。
# 0或不写代表返回所有,1代表返回第一个分组,2代表返回第二个分组
print('匹配成功:', m.group())
print('匹配成功:', m.group(0))
print('匹配成功:', m.group(1))
print('匹配成功:', m.group(2))
else:
print('匹配失败')
匹配普通字符
- 大多数字母和字符一般都会和自身匹配,如正则表达式
r"hello"
会和字符串"hello"
完全匹配。
匹配单个字符(元字符)
代码 | 功能 |
| 匹配任意1个字符(除了 |
| 匹配 |
| 不在 |
| 匹配 |
| 匹配十进制数字,即 |
| 匹配任何非数字字符,即 |
| 匹配任何空白,即 |
| 匹配任何非空白,即 |
| 匹配非特殊字符,即 |
| 匹配特殊字符,即非字母、非数字、非汉字、非下划线 |
匹配多个字符(量字符)
代码 | 功能 |
| 匹配前一个字符出现0次或者无限次,不超过整数界定范围20亿{0,} |
| 匹配前一个字符出现1次或者无限次,即至少有1次{1,} |
| 匹配前一个字符出现1次或者0次,表示某件事物是可选的{0,1} |
| 匹配前一个字符出现 |
| 匹配前一个字符出现从 |
扩展:“?
”
- 当
?
加在+
或*
后面做的是最小匹配,如:
# + 与 ? 组合,如果不加?返回的就是['abbbbbbbb']
re.findall('ab+?','abbbbbbbb')
结果:['ab']
# * 与 ? 组合, 如果不加?返回的就是['abbbbbbbb']
re.findall('ab*?','abbbbbbbb')
结果:['a']
匹配开头和结尾
代码 | 功能 |
| 匹配字符串开头 |
| 匹配字符串结尾 |
匹配分组
代码 | 功能|
| 匹配左右任意一个表达式()
| 作用一:在全匹配中优先输出()
中的内容,常用于爬虫;作用二:将括号中字符作为一个成为整体(分组)\num
| 引用分组num
匹配到的字符串(内容),如果正则前没写r
,就要写成\\num
,即r"\num"
<==>"\\num"
注意:匹配的是内容,不是规则(?P<name>)
| 分组起别名(?P=name)
| 引用别名为name
分组匹配到的字符串
()
的作用一:在全匹配中优先输出()
中得内容
s = '''hhsdj dskj hello src=csvt yes jdjsag
djcasgad src=123 yes jdsa
src=234 yes
hello src=pyhon yse kasdg '''
r1 = r"hello src=(.+ yes)"
re.findall(r1, s)
# 结果:['csvt yes', 'python yes']
()
的作用二:让正则中得一部分成为整体,即分组
# 普通分组:邮箱结尾是.com或.cn,如果不加(),那正则就成了xxx.m或.cn了
email = r"\w{3}@\w+(\.com|\.cn)"
re.match(email, zzz@xx.com')
re.match(email, 'zz@yy.cn')
匿名分组
- 创建正则的分组:用户创建的分组编号是从1开始的;
- 分组引用:将分组匹配到的数据在正则中使用,“
\编号
”表示引用第几个分组的数据。
- 缺点:分组发生变化,分组的编号全部需要修改。
# 需求:匹配出<html>hh</html>
# 原始写法
match_obj = re.match("<[a-zA-Z1-6]+>.*</[a-zA-Z1-6]+>", "<html>hh</html>")
# 利用匿名分组的分组编号简化正则
match_obj = re.match(r"<([a-zA-Z1-6]+)>.*</\1>", "<html>hh</html>")
if match_obj:
print(match_obj.group())
print(match_obj.group(0)) # 等价于上面语句,0表示完整的匹配结果
print(match_obj.group(1)) # 表示第一组正则表达式,这里输出的是“html”
else:
print("匹配失败")
有名分组
- 创建有名分组:
(?P<name>正则)
- 使用有名分组的引用:
(?P=name)
# 需求:匹配出<html><h1>www.itcast.cn</h1></html>
match_obj = re.match(""""<(?P<name1>[a-zA-Z1-6]+)><(?P<name2>
[a-zA-Z1-6]+)>.*
</(?P=name2)></(P=name1)>""",
"<html><h1>www.itcast.cn</h1></html>", re.X) # re.X表示支持将正则写成多行,下面有讲
if match_obj:
print(match_obj.group())
else:
print("匹配失败")
变异标志-flags
参数 | 含义 |
| 简写 |
| 简写 |
| 简写 |
| 简写 |
| 简写 |
re.VERBOSE
或re.X
参数:正则表达式可以写成多行
charref = re.compile(r'''
(
[0-9]+[^0-9] # Decimal form
|0[0-7]+[^0-7] # Octal form
|x[0-9a-fA-F]+[^0-9a-fA-F] # Hexadecimal form
)
''', re.VEROSE)
正则预编译re.compile()
-
re
模块提供了一个正则表达式引擎的接口,可以让你将REstring
编译成对象,并用他们来进行匹配,这样速度比直接利用正则匹配速度快。
编译正则表达式及使用方式:
import re
tel = r"010-?\d{8}$"
p_tel = re.compile(tel) # 将正则表达式生成一个对象
result_list = p_tel.findall("010-12345678") # 使用方式一
result_list = re.findall(p_tel, "010-12345678") # 使用方式二
re.compile()
也可以接受可选的标志参数,常用来实现不同的特殊功能和语法变更,比如忽略大小写:
p = re.compile('ab*', re.IGNORECASE)