工具:正则表达式工具 Match Tracer
https://rubular.com/
https://pythex.org/
概述
正则表达式(Regular Expression)又称规则表达式,是处理字符串的有力工具,是对字符串操作的一种逻辑公式。
正则表达式的本质是用事先定义好的一些特定字符组成的“规则字符串”对字符串的一种过滤逻辑。“规则字符串可以包括普通字符(如a~z之间的英文字母)和特殊字符(称为“元字符”)。
例如正则表达式“0\d{2,3}-d{7,8}”包括普通数字和匹配数字的元字符“\d”,可以过滤或提取字符串中包含的固定电话号码,如“010-88888888” “0711-7777777”等
与Python提供的字符串处理函数相比,正则表达式提供了更加强大的处理功能,可以快速、准确地完成复杂的查找、替换等处理任务;其灵活性、逻辑性、功能性强,而且能用极简单的方式实现字符串的复杂控制
正则表达式处理字符串的过程
(1)编写正则表达式
(2)使用正则表达式引擎对正则表达式进行编译,得到正则表达式对象
(3)通过正则表达式对字符串进行匹配(或过滤),得到匹配(或过滤)结果
使用正则表达式提取字符串中的日期
import re
str='今天是2019-05-01,劳动节!'
reg='\d{2,4}-\d{1,2}-\d{1,2}'
res=re.findall(reg,str) #find all 查找所有匹配结果
print("日期",res)
#
日期 ['2019-05-01']
正则表达式语法
1、正则表达式组成
正则表达式的构造方法和数学表达是的构造方法一样,是用多种元字符与运算发组合在一起创建一个表达是。
组成正则表达式的可以是单个字符、字符集合、字符范围、字符间的选择或者他们之间的任意组合
(1)普通字符
正则表达式中的普通字符包括以下几项
1)英文字母:26个大些英文字母A~Z和26个小写英文字母a~z
2)汉字:Unicode字符集中包括的汉字
3)数字:0~9的10个数字
4)标点符号:如“:” “,”等标点符号
5)其他符号:如“\n”(换行符)“\t”(制表符)等非打印字符
(2)特殊字符
特殊字符指一些有特殊含义的字符。特殊字符一般具有通用性,如"\w"可以表示1位字母、数字、下划线
正则表达式中常用特殊字符包括字符匹配模式、定位符(描述字符串或单词的边界)和限定符(匹配次数)等
字符匹配模式
语法 | 备注 | 解释 | 正则表达式 | 字符串 | 匹配结果 |
---|---|---|---|---|---|
. | 任单 | 匹配除换行符(\n)外的任意单个字符 | a.c | abcalc | abc,alc |
\ | 转义 | 表示位于\之后的转义字符 | a\.c | a.cde | a.c |
| | 或 | 匹配位于|之前或之后的字符 | ab|cd | abcd | ab,cd |
[] | 间单 | 匹配位于[]之中的任意一个字符 | a[bcd]e | abeade | abe,ade |
[a-c]同[abc] | 范围 | 匹配指定范围的任意字符 | [abc] | ace | a,c |
[^a-c]同[^abc] | 以外 | 匹配指定范围外的任意字符 | [^abc] | ace | e |
() | 略迷 | 将()中的内容作为一个整体对待 | (abc)d | abcd | abc |
\d | 1数 | 匹配1位数字 | a\dc | a1cabc | a1c |
\D | 1非数 | 与\d的含义相反 | a\DC | a1cabc | abc |
\w | 字母、数字、下划线 | 匹配1位数字、字母和下划线 | a\wc | abca1c | abc,a1c |
\W | 反 | 与\w的含义相反 | a\Wc | abca c | a c |
\s | 空 | 匹配1位空白字符:<空格>,\t,\n,\r,\f,\v | a\sb | a\nba\tb | ‘a\nb’,‘a\tb’ |
\S | 反 | 与\s的含义相反 | ab\Sd | abcd | abcd |
补充:在findall中,()是接收匹配结果保存到列表中,但是貌似findall有一个bug,当出现多个()的时候,会生成一个元组。可以使用之后提到的(?:)等代替不需要当作结果看待的方法。
Python 正则 findall 多规则匹配问题 结果是元组 解决过程
定位符
语法 | 备注 | 解释 | 正则表达式 | 字符串 | 匹配结果 |
---|---|---|---|---|---|
^ | 句首 | 匹配以^后面的字符或模式开头的字符串 | ^abc | abccc | abc |
$ | 句末 | 匹配以$前面的字符或模式结束的字符串 | abc$ | aaabc | abc |
\b | r、前后s | 匹配单词头或单词尾 | r’\babc\b’ | d abc d | abc |
\B | 反 | 与\b的含义相反 | r’\Babc\B’ | dabcd | abc |
限定符
语法 | 备注 | 解释 | 正则表达式 | 字符串 | 匹配结果 |
---|---|---|---|---|---|
* | 前1字符0+ | 匹配*前一个字符出现0次或者多次 | abc* | ababcabccc | ab,abc,abccc |
+ | 前1字符1+ | 匹配+前一个字符出现1次或多次 | abc+ | ababcabccc | abc,abccc |
? | 01 | 匹配?前一个字符只能出现0次或1次 | abc? | ababc | ab,abc |
{m} | 次 | 匹配前一个字符只能出现m次 | ab{2}c | abcabbcabbbc | abbc |
{m,} | 至少 | 匹配前一个字符至少出现m次 | ab{2,}c | abcabbcabbbc | abbc,abbbc |
{m,n} | 间 | 匹配前一个字符出现m~n次 | ab{1,3}c | abcabbcabbbc | abc,abbc,abbbc |
扩展语法
除上述特殊语法外,Python还允许正则表达式进行语法扩展,以实现更加复杂的字符串处理功能
pattern:模式
零宽断言,后部不能脱离前部使用,否则会触发多余括号
语法 | 备注 | 解释 | 正则表达式 | 字符串 | 匹配结果 |
---|---|---|---|---|---|
(?#pattern) | 注 | 表示注释 | excel(?#EX cell,单元格) | excel电子表格 | excel |
(?:pattern) | 全返 | 匹配但不捕获该匹配的自模式 | win(?:2010)或(?:2010)win | win2010或2010win | win2010或2010win |
(?=pattern) | 后,外返 | 用于正则表达式之后,如果=后的内容在字符串中出现则匹配,但不返回=之后的内容 | win(?=2010) | win2010 | win |
(?!pattern) | 后,非,外返 | 用于正则表达式之后,如果!后的内容在字符串中不出现则匹配,但不返回!之后的内容 | win(?!2010) | win1998 | win |
(?<=) | 前<,外返 | 用于正则表达式之前,如果<=后的内容在字符串中出现则匹配,但不返回<=之后的内容 | (?<=2010)win | 2010win | win |
(?<!pattern) | 前,非,外返 | 用于正则表达式之前,如果<!后的内容在字符串中不出现则匹配,但不返回<!之后的内容 | (?<!2010)win | 1998win | win |
匹配的贪婪模式与非贪婪模式
贪婪模式与非贪婪模式影响的是被量词修饰的子表达式的匹配行为:
(1)贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配
(2)非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配
默认是贪婪模式,在量词后面直接加上一个问号就是非贪婪模式
import re
str="<div></div><div>监督学习</div><div>非监督学习</div><div>半监督学习</div>"
pat1=re.compile('<div>.*</div>')
res1=pat1.findall(str)
print("贪婪匹配:",res1)
pat2=re.compile('<div>.*?</div>')
res2=pat2.findall(str)
print("非贪婪匹配:",res2)
#
贪婪匹配: ['<div></div><div>监督学习</div><div>非监督学习</div><div>半监督学习</div>']
非贪婪匹配: ['<div></div>', '<div>监督学习</div>', '<div>非监督学习</div>', '<div>半监督学习</div>']
.*意味着0或多个换行符外的字符
?意味着思考
使用正则表达式模块处理字符串
Python自1.5版本起增加了Re模块,使Python拥有全部的正则表达式功能
Python标准库Re模块提供两种使用正则表达式处理字符串的方法:
(1)直接调用Re模块中的函数
(2)将正则表达式编译成正则表达式对象后再调用正则表达式对象中的函数
这两种方法的使用形式基本相同,但后者提供了更多、更强大的功能,如可以提高字符串的处理速度等
Re模块中的常用函数
1.匹配函数
(1)re.match()函数
尝试从字符串的起始位置匹配一个模式,若匹配成功则返回一个匹配对象;否则返回None。
match:匹配
pattern:正则表达式
flags:可选标志位
res=re.match(pattern,str,flags=0)
正则表达式常用标志位
修饰符 | 备注 | 描述 |
---|---|---|
re.I | 不区分大小写 | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 | |
re.M | 多行匹配,影响^和$ | |
re.S | 匹配包括换行在内的所有字符 | |
re.U | 根据Unicode字符集解析字符。这个标志影响\w、\W、\b、\B | |
re.X | ^匹配字符串和每行的行首,$匹配字符串和每行的行尾 |
可以使用匹配对象的函数group(num)、groups()、groupdict()来获取匹配结果
(1)group(0):返回包括整个表达式的字符串
(2)group(n1,n2,…):返回一个包含多个组号对应值得元组
(3)groups():返回一个包含所有小组字符串的元组
(4)groupdict():返回一个包含所有经命名匹配小组的字典
使用re.match()函数提取中国国际长途电话的各部分
import re
str='0086-010-88668866'
mat=re.match(r"(?P<nation>\d{4,})-(?P<zone>\d{3,4})-(?P<number>\d{7,8})",str,re.M|re.I)
if mat:
print("mat.group(0):",mat.group(0))
print("mat.group(1):",mat.group(1))
print("mat.group(2):",mat.group(2))
print("mat.group(3):",mat.group(3))
print("mat.group(1,2,3):",mat.group(1,2,3))
print("mat.groups():",mat.groups())
print("mat.groupdict():",mat.groupdict())
else:
print("match匹配不成功")
#
mat.group(0): 0086-010-88668866
mat.group(1): 0086
mat.group(2): 010
mat.group(3): 88668866
mat.group(1,2,3): ('0086', '010', '88668866')
mat.groups(): ('0086', '010', '88668866')
mat.groupdict(): {
'nation': '0086', 'zone': '010', 'number': '88668866'}
(2)re.search()函数
扫描整个字符串并返回第一个成功的匹配对象
res=re.search(pattern,str,flags=0)
import re
str="David的QQ电子邮箱:122345@qq.com"
sea=re.search(r"(?P<user>\d+)@(?P<website>\w+).(?P<extension>\w+)",str,re.M|re.I)
if sea:
print("sea.group(0):",sea.group(0))
print("sea.group(1,2,3):",sea.group(1,2,3))
print("sea.groups():",sea.groups())
print("sea.groupdict():",sea