当前位置: 首页 > 后端技术 > Python

Python正则表达式,这篇文章就够了!

时间:2023-03-26 19:19:15 Python

之前我们讲解了正则表达式语法的起源、发展、流派、语法、引擎、优化等相关知识,今天我们主要来学习一下正则表达式在Python语言中的应用!大多数编程语言的正则表达式设计都是从Perl学来的,所以语法基本类似。不同的是每种语言都有自己的函数来支持正则表达式。今天我们就来了解一下Python中正则表达式的作用。re模块主要定义了9个常量,12个函数,1个异常。猪哥会通过实际的代码案例来讲解每一个常量和函数,让大家更直观的了解它的作用!注:为了避免代码格式混乱,猪哥尽量使用代码截图来演示。一、re模块介绍说起Python正则表达式的支持,大家首先想到的就是re库,它是Python处理文本的标准库。标准库意味着这是一个Python内置模块,不需要额外下载。目前,大约有300个Python内置模块。可以在这里查看Python的所有内置模块:https://docs.python.org/3/py-...因为re是内置模块,不用再下载,import即可使用时直接导入:rere模块官方文档:https://docs.python.org/zh-cn...re模块库源码:https://github.com/python/cpy...2.remoduleconstants常量表示不可改变的变量,一般用于标记。re模块中有9个常量,常量的值都是int类型!从上图我们可以看出,所有的常量都是在RegexFlag枚举类中实现的,这个枚举类是Python3.6的一个改版。在Python3.6之前,常量直接写在re.py中。使用枚举的好处是易于管理和使用!下面就让我们快速了解一下这些常量的作用和使用方法,按常用来排序!1.IGNORECASE语法:re.IGNORECASE或简写为re.I功能:忽略大小写匹配。代码大小写:在默认匹配模式下,大写字母B无法匹配小写字母b,但在忽略大小写模式下可以。2、ASCII语法:re.ASCII或简写为re.A功能:顾名思义,ASCII表示ASCII码,设\w、\W、\b、\B、\d、\D、\s和\S只匹配ASCII,不匹配Unicode。代码示例:在默认的匹配方式下,\w+匹配所有的字符串,但在ASCII模式下,只匹配a、b、c(ASCII编码支持的字符)。注意:这仅对字符串匹配模式有效,对字节匹配模式无效。3、DOTALL语法:re.DOTALL或简写为re.S功能:DOT表示.,ALL表示全部,组合为.匹配所有,包括换行符\n。在默认模式下。无法匹配行字符\n。代码案例:默认匹配方式下,不匹配换行符\n,而是单独匹配字符串;而在re.DOTALL模式下,换行符\n与字符串一起匹配。注意:在默认匹配模式下,.不会匹配换行符\n。4、MULTILINE语法:re.MULTILINE或简写为re.M功能:多行模式,当字符串中有换行符\n时,默认模式不支持换行符特性,如:开头和endoftheline,在多行模式下,支持匹配行首。代码示例:正则表达式中,^表示匹配行的开始。在默认模式下,它只能匹配字符串的开头;在多行模式下,也可以匹配换行符\n之后的字符。注意:在常规语法中,^匹配行的开头,\A匹配字符串的开头。在单线模式下,两者效果相同。在多行模式下,\A无法识别\n。5.VERBOSE语法:re.VERBOSE或简写为re.X功能:详细模式,可以在正则表达式中添加注解!代码示例:正则表达式中的注释默认模式不识别,详细模式识别。当一个正则表达式很复杂时,verbose模式可能会为你提供另一种注释方式,但不应该是炫耀的手段,建议慎重考虑后使用!6.LOCALE语法:re.LOCALE或re.L简称功能:由当前语言环境决定\w,\W,\b,\B并区分大小写匹配,该标签只对bytestyle有效。此标志已正式弃用,因为语言环境机制非常不可靠,一次只能处理一个“自定义”,并且仅适用于8位字节。注:由于该标记已被官方弃用,且朱兄从未使用过,故不给出实际案例!7.UNICODE语法:re.UNICODE或简写为re.U作用:类似ASCII模式,匹配unicode编码支持的字符,但是Python3默认的字符串已经是Unicode了,所以有点多余。8.DEBUG语法:re.DEBUG功能:显示编译时的调试信息。代码示例:虽然在debug模式下确实打印了编译信息,但是猪哥不明白这是什么语言,表达的意思。希望知道的朋友能给我指点一下。9、TEMPLATE语法:re.TEMPLATE或简写为re.T作用:朱兄没看懂TEMPLATE的具体使用。源码注释是这样写的:禁用回溯(disablebacktracking)。了解更多的同学可以留言告诉我们哦!10、常量总结9个常量中,前5个(IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE)有用,两个(LOCALE、UNICODE)官方不推荐使用,两个(TEMPLATE、DEBUG)是实验函数,这不能依赖。常量可以用在re常用函数中,看源码就知道了。常数可以叠加使用,因为常数值都是2的幂,所以可以叠加使用,请用|符号叠加时,不要使用+号!最后,这里用一张思维导图来总结一下re模块中的常量。3.re模块函数re模块中共有12个函数,朱兄将按函数分类进行讲解;这样比较比较好记。1.查找匹配项查找并返回匹配项有3个函数:search、match和fullmatch。它们的区别是:search:在任意位置查找匹配项match:必须从字符串开头开始匹配fullmatch:整个字符字符串与正则表达式完全匹配。下面根据实际代码案例来对比一下:案例一:案例一中,搜索函数匹配字符串中的任意位置。只要有匹配正则表达式的字符串,就匹配成功。事实上,有两个匹配项,但搜索函数值返回一个。match函数是从头开始匹配,字符串开头多了一个字母a,所以无法匹配。fullmatch函数需要完全一样,所以不匹配!案例二:案例二删除了文本开头的字母a,使得match函数可以匹配,但是fullmatch函数还是不能完全匹配!情况三:在情况三中,我们只留下一段文字,与正则表达式一致;这时候fullmatch函数终于可以匹配了。完整案例:注:查找匹配项返回匹配对象(Match)。2.查找多个匹配项目说完查找一个项目,现在我们来看查找多个项目。查找多项的主要函数有:findall函数和finditer函数:findall:从字符串任意位置搜索,返回一个列表finditer:从字符串任意位置搜索,返回一个迭代器。这两个方法基本相似,只是一个返回一个列表,另一个返回一个迭代器。我们知道列表是一次性在内存中生成的,而迭代器是在需要使用的时候一点一点生成的,内存占用比较好。如果可能有大量的匹配项,建议使用finditer功能。一般情况下,使用findall函数基本没有效果。3、splitre.split(pattern,string,maxsplit=0,flags=0)函数:用pattern分隔string,maxsplit表示最大分割数,flags表示pattern,也就是我们上面解释的常量!注意:str模块也有split函数,那么这两个函数怎么选择呢?str.split函数简单,不支持正则拆分,而re.split支持正则拆分。两者的速度如何?猪哥实际测试了一下,在相同数据量下使用了re.split函数和str.split函数。1000多次之后,re.split函数明显变快了,而且次数越多差距越大!所以结论是:在不需要正则支持且数据量和次数较少的情况下使用str.split函数比较合适,否则使用re.split函数。注:具体执行时间与测试数据有关!4.替换和替换主要有sub函数和subn函数,它们的功能是差不多的!先来看看sub函数的用法:re.sub(pattern,repl,string,count=0,flags=0)函数参数说明:repl替换string中pattern匹配的字符,count表示最大值替换次数,flags表示正则表达式的Constant。值得注意的是:sub函数中的入参:repl替换内容可以是字符串也可以是函数!如果repl是一个函数,那么只能有一个入参:Match匹配对象。re.subn(pattern,repl,string,count=0,flags=0)函数与re.sub函数功能相同,但返回一个元组(string,replacementcount)。5.编译正则对象编译函数和模板函数将正则表达式的样式编译成正则表达式对象(正则对象Pattern),与re模块具有相同的正则功能(后面会讲解Pattern正则对象).模板函数与编译函数类似,只是增加了我们之前提到的re.TEMPLATE模式。我们可以看看源码。6.其他re.escape(pattern)可以转义正则表达式中有特殊含义的字符,比如:.或者*,举个实际案例:re.escape(pattern)貌似很好用,省去了我们加转义,但是使用的时候很容易出现转义错误,所以不建议用它来转义,但是建议大家自己手动转义!re.purge()函数的作用是清除正则表达式缓存。有什么样的缓存?看看源码就知道它背后做了什么:方法大概是清除缓存,我们来看具体案例:猪哥使用re.purge()函数来清除缓存之间两个案例,然后对比案例前后源码中的缓存,看看有没有变化!7.小结最后我们来一张思维导图来总结一下re模块中的功能。4.re模块异常re模块也存在正则表达式编译错误。当我们给出的正则表达式是无效的表达式时(即表达式本身有问题),就会抛出异常!我们看一下具体的案例:在上面的案例中,我们可以看到我们在写正则表达式的时候多写了一个括号,导致执行结果报错;并且是在所有其他case执行之前,所以描述在Anerrorwasreportedduringregularexpressioncompilation。注意:这个异常一定是正则表达式本身无效,与要匹配的字符串无关!5.RegularObjectPatternre模块的常量、函数、异常我们已经讲解完了,但是绝对有必要说说regularobjectPattern。1、与re模块的功能一致。re模块的函数中有一个重要的函数compile函数。这个函数可以被预编译并返回一个常规对象。这个常规对象具有与re模块相同的功能。我们先看一下Pattern类的源码。既然是一致的,那到底是用re模块还是用正则对象Pattern呢?而且,可能有同学看过re模块的源码,会发现compile函数和其他re函数(search、split、sub等)其实内部调用的是同一个函数,最后调用的函数是常规对象!也就是说下面两种代码写法的底层实现其实是一样的:#refunctionre.search(pattern,text)#regularobjectfunctioncompile=re.compile(pattern)compile.search(text),那么是否需要使用compile函数得到正则对象后调用查找函数呢?是否可以直接调用re.search?2.官方文档是怎么说的是使用re模块还是使用正则对象模式?官方文档有说明吗?官方文档推荐:多次使用一个正则表达式时,建议使用正则对象Pattern,增加复用性,因为re.compile(pattern)编译出来的模块级函数会被缓存!3.实际测试呢?上面官方文档建议我们在多次使用一个正则表达式时,使用一个正则对象。真的是这样吗?让我们测试一下。猪哥写了两个函数,一个使用re.search函数,一个使用compile.search函数,分别(不是同时)执行count次(从1-10000开始计数),对比一下两者的消耗.小时!得到的结果被猪哥画成折线图:结论是100个周期内两者的速度基本一致,超过100个周期时,函数使用正则对象Pattern的耗时为明显更短,所以它比re模块要快!通过实际测试得知,Python官方文档在多次使用正则表达式时推荐使用正则对象函数,基本是这样!六、注意事项Python正则表达式的基础知识讲解完了,最后说一下需要注意的地方。1.字节串和字符串模式,搜索的字符串可以是Unicode字符串(str)或八位字节字符串(bytes)。但是,Unicode字符串和八位字节字符串不能混用!2、r的作用正则表达式用反斜杠('')表示特殊形式,或将特殊字符转义为普通字符。而反斜杠在普通Python字符串中的作用是一样的,所以就产生了冲突。解决方案是对正则表达式样式使用Python的原始字符串表示法;反斜杠不必在以“r”为前缀的字符串文字中进行任何特殊处理。3.正则搜索函数返回匹配对象查找匹配项(search、match、fullmatch)的函数的返回值是一个匹配对象Match,需要通过match.group()获取匹配值,这很容易忘记。还需要注意:match.group()和match.groups()函数的区别!4.复用一个正则表达式如果要复用一个正则表达式,建议先使用re.compile(pattern)函数返回一个正则对象,再复用这个正则对象,这样会更快!5.Python正则面试笔试可能会遇到需要用到Python正则表达式,但不会太难。只要记住这些方法之间的区别,就可以正确使用它们。基本问题不大。