前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python正则表达式学习拾遗

python正则表达式学习拾遗

作者头像
qsjs
发布2020-06-09 08:59:39
5150
发布2020-06-09 08:59:39
举报
文章被收录于专栏:MyPanda的学习笔记

本篇学习笔记参考re——正则表达式 所作,不明白之处可以参阅上述的官方文档。 因为是个人学习笔记,所以并不会完全介绍所有的正则表达式,而是查漏补缺性质的. A. 在正则匹配的时候,对于匹配数量的控制,常用的特殊字符有 * ? + {m,n} 这4种. 但是这些都是属于“贪婪”匹配,也就是说,这些字符会尽可能多的去进行匹配。 而在实际的情形中,我们可能想进行尽可能少的匹配。这时候有一个办法,就是在这4种匹配的后面跟上 ? 符号。 比如下面的例子:

代码语言:javascript
复制
>>> myfunc="__myfunc__"
>>> re.findall(r'_.*',myfunc)    #默认为“贪婪”匹配,所以匹配了整个字符串. 然后就没有需要匹配的了.
['__myfunc__']
>>> re.findall(r'_.*?',myfunc)  #此时为最小匹配,所以每次匹配的结果只有一个字符‘_', 然后对剩下的字符串继续进行最小匹配,一共获得了4次匹配的结果。
['_', '_', '_', '_']
>>> 

B. [] 该符号的内部表示字符的集合. 其中集合中的任意字符进行匹配。 1). 在该符号的内部,特殊符号都变成了普通字符。 2). 其中 - 在集合内部的头部或者末尾的时候,才表示普通字符。 3). 该集合的内部支持 字符类,比如 [\t] 表示其中一个字符是 tab键的键值 4). 和POSIX 一样,集合内部的 ^ 如果是在首位,那么表示取反,否则是普通字符 5). 如果集合中含有[ , ] 符号,那么用转义符更方便,虽然官方也支持其他的解决办法,个人更乐意用转义符号. C. A|B 这个匹配表示逻辑或,但是 只有 A匹配失败的时候才会匹配B,当然如果有更多个表达式需要匹配,那么可以继续用 | 进行连接,但从左到右,只要匹配成功,那么右边的表达式就不会继续进行匹配. D. (?...) 这是个扩展标记法 (一个 '?' 跟随 '(' 并无含义)。这种扩展通常并不创建新的组合;简单点理解就是: 对正则表达式设置一些 flag, 不同版本的python 可能略有不同,具体可以用命令查看:

代码语言:javascript
复制
[ i for i in dir(re) if len(i)==1]      #我的环境输出为: ['I', 'L', 'M', 'S', 'T', 'U', 'X']

但是在使用 (?...) 这种形式的时候,对应的flag标志都需要小写,只有一个L需要大写,这里原因不清楚,估计是为了更方便的进行识别吧?毕竟大写的i和小写的L在部分字体中是很难通过肉眼区分的. 对于设置正则表达式的flag, 除了使用 (?...) 的方式外,还可以在每个方法中进行指定,比如下列两种方式使用findall方法的结果相同:

代码语言:javascript
复制
>>> re.findall(r"china","China,CHINA,china",re.I)  #传递给findall 方法flag参数  
['China', 'CHINA', 'china']
>>> re.findall(r"(?i)china","China,CHINA,china") #使用 (?...) 的方式,无需传递给findall 方法对应的flag 参数.
['China', 'CHINA', 'china']
>>> 

E. (?:…) 一般情况下,通过() 实现正则表达式的分组,然后在后面可以通过 \n 的方式进行引用,但是如果不希望分组被引用,那么可以用 (?:...)的方式进行分组,这个非常有用哦! F. 在对复杂的字符串进行正则匹配的时候,我们可能需要”对匹配到的内容进行提取或者引用“,这时候最好的方式就是对匹配的内容取个名字,然后引用这个名称 就可以了,Python3.6开始就提供了这种实现: 1). 首先对匹配的内容取一个名字,语法为 (?P<Defined_Name>...),其中 ... 表示匹配的内容,Defined_Name就是定义的名称,这个名称根据你的喜好而定,只要这个名称是有效的python标识符就可以. 简单理解就是: 对于你需要定义名称的正则表达式,需要用() 引用起来,然后写成 (?P<Defined_Name>) 的格式就可以了, 在名称定义好之后,那么就可以进行引用了,目前有三种方式来引用: a. 在同一正则表达式内引用的语法为: (?P=Defined_Name), 例子如下:

代码语言:javascript
复制
>>> s="https://docs.python.org/zh-cn/3.6/library/re.html"        
>>> s2="https://docs.python.org/zh-cn/zh-cn/3.6/library/re.html"
>>> p=r'(.*?)//(.*?)/(?P<myregex>.*?)/(?P=myregex).*?html'  #这里使用 myregex 作上述的Defined_Name.  在同一个正则表达式中对myregex 的引用方式为: (?P=myregex)
>>> re.search(p,s)   #对字符串s, 没有匹配结果
>>> re.search(p,s2)  #对字符串s2,有匹配结果。
<_sre.SRE_Match object; span=(0, 55), match='https://docs.python.org/zh-cn/zh-cn/3.6/library/r>
>>>                                   

b. 对于匹配的对象,那么可以用其 group 方法,然后传递 Defined_Name 作为参数,从而实现引用, 这时候 Defined_Name 做为一个参数,必须是字符串。接着看下面的例子:

代码语言:javascript
复制
>>> r=re.search(p,s2)     #匹配结果保存到 r 中。
>>> r.group("myregex")  #通过group 方法来取 匹配的结果.
'zh-cn'

c. (?P<>) 其实在正则表达式的处理过程中,也是一个有效的分组,所以,我们可以通过 使用分组的方式来引用上述定义了名称的正则表达式,在re.sub方法中,可以用如下的方式:

代码语言:javascript
复制
>>> p
'(.*?)//(.*?)/(?P<myregex>.*?)/(?P=myregex).*?html'            
>>> s2
'https://docs.python.org/zh-cn/zh-cn/3.6/library/re.html'
>>> re.sub(p,"\g<myregex>",s2)            # 正则表达式p 匹配整个s2字符串,然后这里就是把整个字符串s2 替换为 group: myregex 所匹配的内容. 
'zh-cn'
>>> re.sub(p,"\g<3>",s2)   #因为myregex group 对应的是第三个分组,所以可以直接用 分组3 来写,结果是一样的。
'zh-cn'   
>>>                                    

G. (?=…) (?!…) (?<=…) (?<!…) , 这4个表达式,个人认为应该划分为同一个组,都有一个共性: 不占用匹配的位置,仅仅限定了匹配的条件,从这一点上看,有点类似 ^ 和 $ 的意味. 我们很容易注意到后面两个表达式中有”小于号“, 这里的小于号表示前向匹配,毕竟他们不占用匹配的位置,因此这个匹配的条件需要指明:究竟是前向匹配还是后向匹配。 所以另外两个没有”小于号”的就属于后向匹配了。至于“=” 和 “!” 自然就是表示匹配和不匹配了. 这样来理解,个人觉得更容易一些,那么让我们看一些例子吧(注意报错):

代码语言:javascript
复制
>>> s="https://www.jianshu.com/writer#/notes/39570469/notes/fakeurl/preview"
>>> re.findall("(?<=.*#/)notes",s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "E:\Program files\Python\Python36\lib\re.py", line 222, in findall
    return _compile(pattern, flags).findall(string)
  File "E:\Program files\Python\Python36\lib\re.py", line 301, in _compile
    p = sre_compile.compile(pattern, flags)
  File "E:\Program files\Python\Python36\lib\sre_compile.py", line 566, in compile
    code = _code(p, flags)
  File "E:\Program files\Python\Python36\lib\sre_compile.py", line 551, in _code
    _compile(code, p.data, flags)
  File "E:\Program files\Python\Python36\lib\sre_compile.py", line 160, in _compile
    raise error("look-behind requires fixed-width pattern")
sre_constants.error: look-behind requires fixed-width pattern   #这里的报错告诉我们“需要固定长度的pattern". 我们修改下试试!
>>> re.findall("(?<=#/)notes",s)    #这下就成功匹配到了,匹配的结果只有notes, #/ 就两个字符的长度,所以上面的报错就是指  (?<=...) 中 ... 所代表的必须是固定长度. 并且 #/ 不占用匹配的结果。
['notes']
>>>   
>>> re.findall("(?<!#/)notes",s)    #验证  (?<!...) 的结果.
['notes']                                                

验证完了前向匹配条件,我们来验证 后向匹配的表达式,注意看下面的测试结果:

代码语言:javascript
复制
>>> s
'https://www.jianshu.com/writer#/notes/39570469/notes/fakeurl/preview'
>>> re.findall("(?=/[0-9]{8})notes",s)
[]             #很奇怪,结果居然是空的,不应该是 notes 吗? 想一下 ^ 指定匹配的字符串的开头,那么必须写在字符串的最开始,而 $ 用于指定字符串的结尾条件,那么$必须写在字符串的末尾,所以 (?=...) 作为后向匹配的条件自然要写到 被匹配字符串的后面,那么 我们修改下看看: 
>>> re.findall("notes(?=/[0-9]{8})",s)           #这下结果就正常了.
['notes']
>>> re.findall("notes(?!/[0-9]{8})",s)           #这个结果也是正常的
['notes']
>>>                                                                      

H. 关于python中的一些控制字符: \b 和 \B 都是边界控制字符,对于匹配的字符串的相邻字符进行筛选,从而实现更精准的匹配. 在这里涉及到正则表达式中的”word“的概念。 在ansic 编码下,对word的定义是: 数字,字母,以及下划线组成的字符串,其他的字符不属于word的组成部分。 而 \b 表示匹配的字符串其相邻的字符 不能是word的组成,否则不匹配。而\B 则表示,其匹配的字符串的 相邻字符必须是word的组成,否则不匹配,我们看下面的例子:

代码语言:javascript
复制
>>> re.findall(r"(?i)\bchina\b","China,china_,CHINA,China0,0china,MChInAN") #china 单词的相邻字符不能是word的组成.
['China', 'CHINA']
>>> re.findall(r"(?i)\Bchina\B","China,china_,CHINA,China0,0china,MChInAN")  #china单词的相邻字符必须是word的组成.
['ChInA']
>>> re.findall(r"(?i)\bchina\B","China,china_,CHINA,China0,0china,MChInAN") #china单词的前面不能是word的组成,而后面必须是word的组成字符.
['china', 'China']
>>> re.findall(r"(?i)\Bchina\b","China,china_,CHINA,China0,0china,MChInAN") #china 单词的前面必须是word的组成,而后面不能是word的组成.
['china']
>>>                                                                                    

\d , \D 这两个就比较简单了,前面表示数字,后面表示非数字. \w 就表示上述所述的word. \W 就是\w的取反.

其他更多内容,请参考python的官方文档或者帮助,希望读到此片文章的你也可以获益哦!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档