嗨喽,小伙伴们大家早上好,中午好,晚上好呀,
又有好久没更新了,今天给大家分享一下python的正则表达式。
众所周知,python的正则表达式这类的工具类知识经常不用的话,容易忘记,所以我把它放在了代码中,需要用时,看看代码即可,里面的注释非常完整,详细,欢迎大家复制~~~
我们主要介绍re模块:
import re
"""
:author 易果啥笔
:apiNote re模块主要定义了9个常量、12个函数
:data 2022.01.18
"""
def regex_flags(flag):
# 9个常量
if flag == 'IGNORECASE':
'''
语法: re.IGNORECASE
作用: 进行忽略大小写匹配。
'''
text = '易果啥笔a'
pattern = r'易果啥笔A'
print("默认模式:", re.findall(pattern, text))
print("忽略大小写模式:", re.findall(pattern, text, re.IGNORECASE))
if flag == 'ASCII':
'''
语法: re.ASCII
作用: 顾名思义,ASCII表示ASCII码,
让 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII,
而不是Unicode。
在默认匹配模式下\w+匹配到了下面例子的所有字符串,
而在ASCII模式下,只匹配到了a、b、c(ASCII编码支持的字符)。
注意:这只对字符串匹配模式有效,对字节匹配模式无效。
'''
text = 'a易果啥笔b易果啥笔c'
pattern = r'\w+'
print("默认模式Unicode:", re.findall(pattern, text))
print("ASCII模式:", re.findall(pattern, text, re.ASCII))
if flag == 'DOTALL':
'''
语法: re.DOTALL
作用: DOT表示.,ALL表示所有,连起来就是 .匹配所有,
包括换行符\n。默认模式下.是不能匹配换行符\n的。
'''
text = 'a易果啥笔\n易果啥笔c'
pattern = r'.*'
print(text)
print("默认模式:", re.findall(pattern, text))
print("DOTALL模式:", re.findall(pattern, text, re.DOTALL))
if flag == 'MULTILINE':
'''
语法: re.MULTILINE
作用: 多行模式,当某字符串中有换行符\n,默认模式下是不支持换行符特性的,
比如:行开头 和 行结尾,而多行模式下是支持匹配行开头的。
下面的例子中,正则表达式中^表示匹配行的开头,
默认模式下它只能匹配字符串的开头;而在多行模式下,它还可以匹配换行符\n后面的字符。
注意:正则语法中^匹配行开头、\A匹配字符串开头,
单行模式下它两效果一致,多行模式下\A不能识别\n。
'''
text = '易果啥笔\n易果啥笔'
pattern = r'^易果啥笔'
print(text)
print("默认模式:", re.findall(pattern, text))
print("MULTILINE模式:", re.findall(pattern, text, re.MULTILINE))
if flag == 'VERBOSE':
'''
语法: re.VERBOSE
作用: 详细模式,简单来说,在正则表达式中可以加注释
默认模式下并不能识别正则表达式中的注释,而详细模式是可以识别的。
当一个正则表达式十分复杂的时候,详细模式能为你提供另一种注释方式,
'''
text = '易果啥笔'
pattern = r'''
^易果 # 量词
啥笔 # 名词
'''
print(text)
print("默认模式:", re.findall(pattern, text))
print("MULTILINE模式:", re.findall(pattern, text, re.VERBOSE))
if flag == 'LOCALE':
'''
语法: re.LOCALE
作用: 由当前语言区域决定 \w, \W, \b, \B 和大小写敏感匹配,
这个标记只能对byte样式有效。官方已经不推荐使用,
'''
if flag == 'UNICODE':
'''
语法: re.UNICODE
作用: 与 ASCII 模式类似,匹配unicode编码支持的字符,
但是 Python 3 默认字符串已经是Unicode,所以有点冗余。
'''
if flag == 'DEBUG':
'''
语法: re.DEBUG
作用: 显示编译时的debug信息,目前这个debug信息笔者不太清楚
'''
text = '异国傻逼a'
pattern = r'异国傻逼A'
print("DEBUG模式:", re.findall(pattern, text, re.DEBUG | re.IGNORECASE))
if flag == 'TEMPLATE':
'''
语法: re.TEMPLATE
作用: 没搞懂TEMPLATE的具体用处,
源码注释中写着:disable backtracking(禁用回溯)
'''
'''
常量总结:
1. 9个常量中,前5个(IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE)有用处,
两个(LOCALE、UNICODE)官方不建议使用、
两个(TEMPLATE、DEBUG)试验性功能,不能依赖。
2. 常量在re模块的常用函数中都可以使用,查看源码可得知。
3. 常量可叠加使用,因为常量值都是2的幂次方值,
所以是可以叠加使用的,叠加时请使用 | 符号,请勿使用 + 符号
'''
def regex_function(funcition_name):
"""
re模块有12个函数
"""
"""
1.查找一个匹配项
查找并返回一个匹配项的函数有3个:search、match、fullmatch,
他们的区别分别是:
search: 查找任意位置的一个匹配项
match: 必须从字符串开头匹配
fullmatch: 整个字符串与正则完全匹配
查找一个匹配项 返回的都是一个匹配对象(Match),其含有的方法有:
1. group(index) 某个组匹配的结果(无匹配时调用会报错)
2. groups() 所有分组的匹配结果,每个分组组成的结果以列表返回(无匹配时调用会报错)
3. groupdict() 返回组名作为key,每个分组的匹配结果作为value的字典
4. span([group]) 获取组的开始和结束位置
5. expand(template) 使用组的匹配结果来替换template中的内容,并把替换后的字符串返回
"""
if funcition_name == 'one_match':
text = 'I have 9 students.'
# (?P<label>...)可以给正则中的组添上一个标签label,这样match对象可以使用标签名来访问对应组的匹配结果
pattern = r'(?P<one>\w+) (?P<two>\w+) (?P<three>\d+) (?P<four>\w+)' # 四个组
print("search:", re.search(pattern, text).group(0)) # 所有的组 I have 9 students
print("search:", re.search(pattern, text).groups()) # 所有的组 ('I', 'have', '9', 'students')
print("search:", re.search(pattern, text).group(1)) # 第一组 I
print("search:", re.search(pattern, text).group(2)) # 第二组 have
print("search:", re.search(pattern, text).group(3)) # 第三组 9
print("search:", re.search(pattern, text).groupdict()['one']) # I
# groupdict() 调用结果:{'one': 'I', 'two': 'have', 'three': '9', 'four': 'students'}
# print("match:", re.match(pattern,text))
# print("fullmatch:", re.fullmatch(pattern,text))
if funcition_name == 'many_match':
"""
2.查找多个匹配项
查找多项函数主要有:findall函数 与 finditer函数:
1. findall: 从字符串任意位置查找,返回一个列表
2. finditer:从字符串任意位置查找,返回一个迭代器
两个方法基本类似,
只不过一个是返回列表,一个是返回迭代器。
列表是一次性生成在内存中,而迭代器是需要使用时一点一点生成出来的,内存使用更优。
如果可能存在大量的匹配项的话,建议使用finditer函数,一般情况使用findall函数基本没啥影响。
"""
text = '我的电话号码是:17377762736,我的妹妹的电话号码是:18976562836,我们都住在3601寝室,我的帐号是11290378914。'
pattern = r'(?P<phone>1[2-9][1-9]{9})'
print(re.findall(pattern, text))
# ['17377762736', '18976562836']
match_list = list(re.finditer(pattern, text))
# match_list中是若干个match对象:
# [<re.Match object; span=(8, 19), match='17377762736'>, <re.Match object; span=(31, 42), match='18976562836'>]
if funcition_name == 'split':
"""
3.分割
re.split(pattern, string, maxsplit=0, flags=0) 函数:
用 pattern 分开 string , maxsplit表示最多进行分割次数,值为0表示不限分割次数
flags表示模式,就是上面的常量!
"""
text = 'Haha,Heihei,Hehe.哈哈'
pattern = r'[,,.]'
print("正则表达式进行分割:", re.split(pattern, text, maxsplit=0, flags=0))
# ['Haha', 'Heihei', 'Hehe', '哈哈']
"""
注意:str模块也有一个 split函数 ,那这两个函数该怎么选呢?
str.split函数功能简单,不支持正则分割,而re.split支持正则。
在 不需要正则支持 且 数据量和数次不多 的情况下使用str.split函数更合适,
反之则使用re.split函数。
"""
if funcition_name == 'replace':
"""
4.替换
替换主要有sub函数 与 subn函数,他们功能类似
sub函数的用法:
re.sub(pattern, repl, string, count=0, flags=0)
函数参数讲解:repl替换掉string中被pattern匹配的字符,
count表示最大替换次数,flags表示正则表达式的常量。
"""
text = 'Haha,Heihei,Hehe.哈哈'
pattern = r'[,,.]'
print("sub函数替换:", re.sub(pattern, '...', text, count=0, flags=0))
# sub函数替换: Haha...Heihei...Hehe...哈哈
'''
re.subn(pattern, repl, string, count=0, flags=0)
返回一个元组,第一个元素即为sub()的返回值,第二个元素表示匹配成功的次数。
'''
print("subn函数替换:", re.subn(pattern, '...', text, count=0, flags=0))
# ('Haha...Heihei...Hehe...哈哈', 3)
"""
如果想要对替换的所有字符串中的某个字符串单独替换成其他字符串,可以传入repl的函数形式:
"""
matchobj = lambda matchobj: '......' if matchobj.group(0) != ',' else '。'
print("函数替换:", re.sub(pattern, matchobj, text, flags=re.IGNORECASE))
# Haha。Heihei......Hehe......哈哈
def pattern_obj():
"""
前面我们一直使用的是re.啥啥啥,这个re我们也可以自定义,这就是Pattern对象,即正则对象Pattern。
"""
text = '我的电话号码是:17377777777,我的妹妹的电话号码是:18977777777,我们都住在3601寝室,我的帐号是11111111111。'
pattern = r'(?P<phone>1[2-9][0-9]{9})'
pattern_obj = re.compile(pattern) # pattern_obj = re.compile(r'(?P<phone>1[2-9][1-9]{9})')
# 此时得到的pattern_obj就相当于re,可以调用其split(),sub(),match(),search()函数等
match_result1 = pattern_obj.findall(text) # 已有正则,只需传入待查找的文本即可
print(match_result1)
"""
既然有re就够了,为什么还要有pattern对象呢?
官方文档推荐:在多次使用 "一个正则表达式" 时推荐使用正则对象Pattern以增加复用性,
因为通过 re.compile(pattern) 编译后的模块级函数会被缓存。。。
比如前面的pattern_obj这个pattern对象,用于从一串文本中找出电话号码,我们可以反复使用这个对象:
"""
text2 = '我爸爸的电话号码是11011011101,我姐姐的电话号码是12345678910,呀呀呀'
# 反复使用pattern_obj对象
match_result2 = pattern_obj.findall(text2)
print(match_result2)
"""
常量也可以简写,具体参考下面的re模块源码:
class RegexFlag(enum.IntFlag):
ASCII = A = sre_compile.SRE_FLAG_ASCII # assume ascii "locale"
IGNORECASE = I = sre_compile.SRE_FLAG_IGNORECASE # ignore case
LOCALE = L = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale
UNICODE = U = sre_compile.SRE_FLAG_UNICODE # assume unicode "locale"
MULTILINE = M = sre_compile.SRE_FLAG_MULTILINE # make anchors look for newline
DOTALL = S = sre_compile.SRE_FLAG_DOTALL # make dot match newline
VERBOSE = X = sre_compile.SRE_FLAG_VERBOSE # ignore whitespace and comments
# sre extensions (experimental, don't rely on these)
TEMPLATE = T = sre_compile.SRE_FLAG_TEMPLATE # disable backtracking
DEBUG = sre_compile.SRE_FLAG_DEBUG # dump pattern after compilation
"""
if __name__ == '__main__':
"""
注意:Python中字符串前面加上r表示原生字符串,试比较下面两行:
"""
# print("\\\\") # \\
# print(r'\\\\') # \\\\
# pattern_obj()
# regex_function("replace")
# regex_flags("MULTILINE")
觉得有帮助的小伙伴们点个赞鼓励支持一下吧~~~