- Python实践:Python文本处理之正则表达式
- 初级三板斧
- 进阶登堂入室
- Python实战
- 分割
- 分组
- 隋唐练习
- 参考资料
正则表达式是一种用来匹配字符串的强有力的武器,利用 字符来匹配字符的思想,基于显示规则进行模式匹配,可以高效组合成不同样式的字符串,迅速处理字符串。
相信我,学会正则表达式,你在以后的文本处理时,一定会感谢我。温馨提示,建议配合《廖雪峰的Python正则表达式教程》研读,见文末参考资料1。
初级三板斧基础元字符意义总结如下,日常情况都是以下举例的组合:
-
\d
,表示一个数字 -
\w
,表示一个字母或数字 -
.
, 表示任意一个字符,如:'py.‘可以匹配’pyc’、‘pyo’、'py!'等 -
*
, 表示任意个字符(包括0个),对前一个字符模式重复任意次 -
+
, 表示至少一个字符 -
?
, 表示0个或1个字符 -
{}
, 表示自定义个字符个数,修饰前面一个变量最长的字符个数,如{n}表示n个字符;{n,m}表示n-m个字符,可取到m个字符 -
\s
, 表示一个空白符,如空格Space、Tab等,\s+
可表示至少有一个空格
组合示例:
\d{3,8}
,表示3-8个数字组成的字符串,例如’123’或’12345678’\d{3}
,表示3个数字,例如’010’\w.
,表示任意一个字符(字符或数字)配一个任意字符, 如’a.', ‘p!’[A-Z]
, 表示可能有0或1个<符号,后面接一个大写字母,如‘- ``\s+`,表示至少有一个空白符,如’ ', ’ ’
高频问题总结如下:
-
转义问题,标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
- 如:
'-_?.'
,都是特殊字符,在正则表达式中,要用\
转义 - 如:
r'py\.'
,才能查找py.这样的字符串
- 如:
-
|
,选择分支表示或的关系,A|B可以匹配A或B,如(P|p)ython
可以匹配’Python’或者’python’。 -
[]
,表示当前一个字符的范围,大于两种的可能;如:[a-zA-Z\_][0-9a-zA-Z\_]{0, 19}
,前面1个字符+后面最多19个字符 -
^
,表示行的开头,如^\d
,表示必须以数字开头。 -
$
,表示行的结束,如\d$
,表示必须以数字结束。 -
()
,分组功能,(xyz) 字符组,按照确切的顺序匹配字符 xyz。 -
[^]
,否定字符类。匹配方括号中不包含的任意字符
组合示例:
^(P|p)y
,表示首行以P或p开头,第二个字符为y的字符串^py&
,表示整行匹配,行首以p开头,且中间无字符,行尾以y结束[^\w]+
,表示所有非字母或数字的字符串
Python用re
模块来使用正则表达式功能,原因是正则表达式的英文为“Regular Expression”,常见缩写为:regex 或 regexp。
import re # 导入正则表达式模块
由于Python的字符串本身也用\
转义,所以一般使用时要对\
本身进行转义,变成\
。比如:
s = 'ABC\-001' # Python的字符串
# 对应的正则表达式字符串变成:
# 'ABC\-001'
但还有个更优雅的解决办法,强烈推荐:
- 在字符串前加r,表示按字面意思处理,不转义,可达到相同效果
- 当然,此时\n,\t,%d等转义字符就无转义功能了
s = r'ABC\-001' # Python的字符串
分割
根据re的split()
函数,基于正则表达式的Python字符串分割,说明如下:
re.split(r'pattern', 'str')
- 入参1:匹配pattern,入参2:带查找字符串
实例如下:
# 功能:去除空格等空白符,+表示以上形式的字符至少有一个
re.split(r'\s+', 'a b c')
# 功能:去除空白符和逗号,+表示以上形式的字符至少有一个
re.split(r'[\s\,]+', 'a,b, c d')
分组
主要知识点:
- groups()函数
- ()的用法,每个()对应分离出一组结果
再以分离识别时间字符串例子进行说明。
t = '19:05:30'
m = re.match(r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$', t)
m.groups() # >>> ('19', '05', '30')
分段理解:
- (0[0-9]|1[0-9]|2[0-3]|[0-9]),表示识别第一个组,即’19:05:30’中的19
- 第一组,总体有4种可能形式,用逻辑或
|
连接0*
1*
2*
*(一位数表示场景)
- 0[0-9],场景1,表示0字符开头,加一个0-9数字, 00-09
- 1[0-9],场景2,10-19
- 2[0-3],场景3,20-23,注意没有24点,因为有00:00
- [0-9], 场景4,0-9,处理仅一位数的场景
此外,要注意贪心匹配法的问题,以下内容摘自廖雪峰正则表达式文章。
# 默认贪心匹配,即大嘴法,能跟更多的满足条件的组合
>>> re.match(r'^(\d+)(0*)$', '102300').groups()
>>> ('102300', '')
# 必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:
>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
>>> ('1023', '00')
行文至此,细心的读者可能发现,一直都是在处理英文字符,如果要查找中文样式的字符如何处理呢?
正则表达式匹配汉字核心思路是:在unicode编码模式下,汉字编码范围:\u4e00-\u9fa5
,可据此进行表征,详细内容见:此文。
来自廖雪峰文章的作业,根据以上知识试解决以下两个问题。
- 问题1:一个验证Email地址的正则表达式。如以下Email格式:someone@gmail.com;bill.gates@microsoft.com
- 问题2:提取出带名字的Email地址。如:
tom@voyager.org => Tom Paris;bob@example.com => bob
参考代码及详解如下:
def is_valid_email(addr):
# [\w.]+ 表示至少有任意一个字母或者数字或者.出现,多个类似数字依然认可
# 直到遇到@
# \w+ 表示只有字符(字母或数字)出现
# 直到遇到.com$一直到结尾
# re_email = re.compile(r'[\w.]+@\w+.com$') # 将正则表达式预编译,以便经常调用
# if re_email.match(addr):
if re.match(r'[\w.]+@\w+.com$', addr):
return True
else:
return False
def name_of_email(addr):
#
# ([A-Za-z\s]+),对以下模式字符串:仅含字母和空格的内容,分组提取到group1
# (),一个括号表示分一个组
res = re.match(r'([A-Za-z\s]+)>?', addr)
return res.group(1) # group是个函数,1是入参,表示分组后的第一个结果,0则表示分组前的内容
参考资料
- 廖雪峰正则表达式博客,讲解清晰,简明易懂,入门必备:link
- 好心人总结的进阶补充手册,概况全面:link
- 菜鸟教程,体系化总结:link
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)