以前咱们讲解了 正则表达式语法 的起源、发展、流派、语法、引擎、优化等相关知识,今天咱们主要来学习一下 正则表达式在 Python语言 中的应用!html
大多数编程语言的正则表达式设计都师从Perl,因此语法基本类似,不一样的是每种语言都有本身的函数去支持正则,今天咱们就来学习 Python中关于 正则表达式的函数。
re模块主要定义了9个常量、12个函数、1个异常,每一个常量和函数猪哥都会经过实际代码案例讲解,让你们能更直观的了解其做用!python
注:为避免出现代码格式错乱,猪哥尽可能使用代码截图演示哦。git
聊到Python正则表达式的支持,首先确定会想到re
库,这是一个Python处理文本的标准库。github
标准库的意思表示这是一个 Python内置模块,不须要额外下载,目前Python内置模块大概有300个。能够在这里查看Python全部的内置模块: https://docs.python.org/3/py-...
由于re是内置模块,因此不须要再下载,使用时直接引入便可:面试
import re
re模块官方文档:https://docs.python.org/zh-cn...
re模块库源码:https://github.com/python/cpy...正则表达式
常量即表示不可更改的变量,通常用于作标记。编程
re模块中有9个常量,常量的值都是int类型!
上图咱们能够看到,全部的常量都是在RegexFlag枚举类来实现,这是在Python 3.6作的改版。在Python 3.6之前版本是直接将常量写在re.py中,使用枚举的好处就是方便管理和使用!segmentfault
下面咱们来快速学习这些常量的做用及如何使用他们,按经常使用度排序!缓存
语法: re.IGNORECASE 或简写为 re.I编程语言
做用: 进行忽略大小写匹配。
代码案例:
在默认匹配模式下大写字母B没法匹配小写字母b,而在 忽略大小写 模式下是能够的。
语法: re.ASCII 或简写为 re.A
做用: 顾名思义,ASCII表示ASCII码的意思,让 \w
, \W
, \b
, \B
, \d
, \D
, \s
和 \S
只匹配ASCII,而不是Unicode。
代码案例:
在默认匹配模式下\w+
匹配到了全部字符串,而在ASCII模式下,只匹配到了a、b、c(ASCII编码支持的字符)。
注意:这只对字符串匹配模式有效,对字节匹配模式无效。
语法: re.DOTALL 或简写为 re.S
做用: DOT表示.
,ALL表示全部,连起来就是.
匹配全部,包括换行符\n
。默认模式下.
是不能匹配行符\n
的。
代码案例:
在默认匹配模式下.
并无匹配换行符\n
,而是将字符串分开匹配;而在re.DOTALL模式下,换行符\n
与字符串一块儿被匹配到。
注意:默认匹配模式下.
并不会匹配换行符\n
。
语法: re.MULTILINE 或简写为 re.M
做用: 多行模式,当某字符串中有换行符\n
,默认模式下是不支持换行符特性的,好比:行开头 和 行结尾,而多行模式下是支持匹配行开头的。
代码案例:
正则表达式中^
表示匹配行的开头,默认模式下它只能匹配字符串的开头;而在多行模式下,它还能够匹配 换行符\n
后面的字符。
注意:正则语法中^
匹配行开头、\A
匹配字符串开头,单行模式下它两效果一致,多行模式下\A
不能识别\n
。
语法: re.VERBOSE 或简写为 re.X
做用: 详细模式,能够在正则表达式中加注解!
代码案例:
默认模式下并不能识别正则表达式中的注释,而详细模式是能够识别的。
当一个正则表达式十分复杂的时候,详细模式或许能为你提供另外一种注释方式,但它不该该成为炫技的手段,建议谨慎考虑后使用!
语法: re.LOCALE 或简写为 re.L
做用: 由当前语言区域决定 \w
, \W
, \b
, \B
和大小写敏感匹配,这个标记只能对byte样式有效。这个标记官方已经不推荐使用,由于语言区域机制很不可靠,它一次只能处理一个 "习惯”,并且只对8位字节有效。
注意: 因为这个标记官方已经不推荐使用,并且猪哥也没使用过,因此就不给出实际的案例!
语法: re.UNICODE 或简写为 re.U
做用: 与 ASCII 模式相似,匹配unicode编码支持的字符,可是 Python 3 默认字符串已是Unicode,因此有点冗余。
语法: re.DEBUG
做用: 显示编译时的debug信息。
代码案例:
虽然debug模式下确实会打印编译信息,但猪哥并不理解这是什么语言 以及表达的含义,但愿了解的朋友能不吝赐教。
语法: re.TEMPLATE 或简写为 re.T
做用: 猪哥也没搞懂TEMPLATE的具体用处,源码注释中写着:disable backtracking(禁用回溯),有了解的同窗能够留言告知!
|
符号,请勿使用+
符号!最后来一张思惟导图总结一下re模块中的常量吧。
re模块有12个函数,猪哥将以功能分类来说解;这样更具备比较性,同时也方便记忆。
查找并返回一个匹配项的函数有3个:search、match、fullmatch,他们的区别分别是:
咱们再来根据实际的代码案例比较:
案例1:
案例1中search函数是在字符串中任意位置匹配,只要有符合正则表达式的字符串就匹配成功,其实有两个匹配项,但search函数值返回一个。
而match函数是要从头开始匹配,而字符串开头多了个字母a
,因此没法匹配,fullmatch函数须要彻底相同,故也不匹配!
案例2:
案例2删除了text最开头的字母a,这样match函数就能够匹配啦,而fullmatch函数依然不能彻底匹配!
案例3:
案例3中,咱们只留下一段文字,而且与正则表达式一致;这时fullmatch函数终于能够匹配了。
完整案例:
注意:查找 一个匹配项 返回的都是一个匹配对象(Match)。
讲完查找一项,如今来看看查找多项吧,查找多项函数主要有:findall函数 与 finditer函数:
两个方法基本相似,只不过一个是返回列表,一个是返回迭代器。咱们知道列表是一次性生成在内存中,而迭代器是须要使用时一点一点生成出来的,内存使用更优。
若是可能存在大量的匹配项的话,建议使用finditer函数,通常状况使用findall函数基本没啥影响。
re.split(pattern, string, maxsplit=0, flags=0) 函数:用 pattern 分开 string , maxsplit表示最多进行分割次数, flags表示模式,就是上面咱们讲解的常量!
注意:str
模块也有一个 split函数 ,那这两个函数该怎么选呢?
str.split函数功能简单,不支持正则分割,而re.split支持正则。
关于两者的速度如何? 猪哥实际测试一下,在相同数据量的状况下使用re.split
函数与str.split
函数执行次数 与 执行时间 对比图:
经过上图对比发现,1000次循环之内str.split
函数更快,而循环次数1000次以上后re.split
函数明显更快,并且次数越多差距越大!
因此结论是:在 不须要正则支持 且 数据量和数次很少 的状况下使用str.split
函数更合适,反之则使用re.split
函数。
注:具体执行时间与测试数据有关!
替换主要有sub函数 与 subn函数,他们功能相似!
先来看看sub函数的用法:
re.sub(pattern, repl, string, count=0, flags=0) 函数参数讲解:repl替换掉string中被pattern匹配的字符, count表示最大替换次数,flags表示正则表达式的常量。
值得注意的是:sub函数中的入参:repl替换内容既能够是字符串,也能够是一个函数哦! 若是repl为函数时,只能有一个入参:Match匹配对象。
re.subn(pattern, repl, string, count=0, flags=0) 函数与 re.sub函数 功能一致,只不过返回一个元组 (字符串, 替换次数)。
compile函数 与 template函数 将正则表达式的样式编译为一个 正则表达式对象 (正则对象Pattern),这个对象与re模块有一样的正则函数(后面咱们会讲解Pattern正则对象)。
而template函数 与 compile函数 相似,只不过是增长了咱们以前说的re.TEMPLATE 模式,咱们能够看看源码。
re.escape(pattern) 能够转义正则表达式中具备特殊含义的字符,好比:.
或者 *
,举个实际的案例:
re.escape(pattern) 看似很是好用省去了咱们本身加转义,可是使用它很容易出现转义错误的问题,因此并不建议使用它转义,而建议你们本身手动转义!
re.purge() 函数做用就是清除 正则表达式缓存,具体有什么缓存呢?咱们来看看源码就知道它背地里干了 什么:
看方法大概是清除缓存吧,咱们再来看看具体的案例:
猪哥在两个案例之间使用了re.purge() 函数清除缓存,而后分别比较先后案例源码里面的缓存,看看是否有变化!
一样最后来一张思惟导图总结一下re模块中的函数吧。
re模块还包含了一个正则表达式的编译错误,当咱们给出的正则表达式是一个无效的表达式(就是表达式自己有问题)时,就会raise一个异常!
咱们来看看具体的案例吧:
上图案例中咱们能够看到,在编写正则表达式中咱们多写了一个括号,这致使执行结果报错;并且是在其余全部案例执行以前,因此说明是在正则表达式编译时期就报错了。
注意:这个异常必定是 正则表达式 自己是无效的,与要匹配的字符串无关!
关于re
模块的常量、函数、异常咱们都讲解完毕,可是彻底有必要再讲讲正则对象Pattern。
在re
模块的函数中有一个重要的函数 compile函数 ,这个函数能够预编译返回一个正则对象,此正则对象拥有与re
模块相同的函数,咱们来看看Pattern类的源码。
既然是一致的,那到底该用re模块 仍是 正则对象Pattern ?
并且,有些同窗可能看过re
模块的源码,你会发现其实compile函数 与 其余 re函数(search、split、sub等等) 内部调用的是同一个函数,最终仍是调用正则对象的函数!
也就是说下面 两种代码写法 底层实现 实际上是一致的:
# re函数 re.search(pattern, text) # 正则对象函数 compile = re.compile(pattern) compile.search(text)
那还有必要使用compile函数 获得正则对象再去调用 search函数 吗?直接调用re.search 是否是就能够?
关于到底该用re模块 仍是 正则对象Pattern ,官方文档是否有说明呢?
官方文档推荐:在屡次使用某个正则表达式时推荐使用正则对象Pattern 以增长复用性,由于经过 re.compile(pattern) 编译后的模块级函数会被缓存!
上面官方文档推荐咱们在 屡次使用某个正则表达式时使用正则对象,那实际状况真的是这样的吗?
咱们在实测一下吧
猪哥编写了两个函数,一个使用re.search函数 另外一个使用 compile.search函数 ,分别(不一样时)循环执行count次(count从1-1万),比较二者的耗时!
得出的结果猪哥绘制成折线图:
得出的结论是:100次循环之内二者的速度基本一致,当超出100次后,使用 正则对象Pattern 的函数 耗时明显更短,因此比re模块 要快!
经过实际测试得知:Python 官方文档推荐 屡次使用某个正则表达式时使用正则对象函数 基本属实!
Python 正则表达式知识基本讲解完毕,最后稍微给你们提一提须要注意的点。
模式和被搜索的字符串既能够是 Unicode 字符串 (str) ,也能够是8位字节串 (bytes)。 可是,Unicode 字符串与8位字节串不能混用!
正则表达式使用反斜杠('')来表示特殊形式,或者把特殊字符转义成普通字符。
而反斜杠在普通的 Python 字符串里也有相同的做用,因此就产生了冲突。
解决办法是对于正则表达式样式使用 Python 的原始字符串表示法;在带有 'r' 前缀的字符串字面值中,反斜杠没必要作任何特殊处理。
查找一个匹配项(search、match、fullmatch)的函数返回值都是一个 匹配对象Match ,须要经过match.group() 获取匹配值,这个很容易忘记。
另外还须要注意:match.group() 与match.groups() 函数的差异!
若是要重复使用某个正则表达式,推荐先使用 re.compile(pattern)函数 返回一个正则对象,而后复用这个正则对象,这样会更快!
笔试可能会遇到须要使用Python正则表达式,不过不会太难的,你们只要记住那几个方法的区别,会正确使用,基本问题不大。