鱼c笔记——Python正则表达式(二):特殊符号及贪婪非贪婪

在Python中,正则表达式是以字符串的形式来描述的。正则表达式的强大之处在于特殊符号的应用。

特殊符号是由 元字符 和 由反斜杠加上普通符号 这两部分组成

元字符有:  

. ^ $ * + ? { } [ ] \ | ( )


元字符用法例子:

| 广告符:相当于逻辑或

>>> import re

>>> re.search(r'instan(c|s)e', 'instance')
<_sre.SRE_Match object; span=(0, 8), match='instance'>

>>> re.search(r'instan(c|s)e', 'instanse')
<_sre.SRE_Match object; span=(0, 8), match='instanse'>

^脱字符:匹配输入字符串的开始位置(匹配的字符串只能在字符串的开始位置)

>>> re.search(r'^simple', 'This is a simple example')  #不在开头就匹配不上

>>> re.search(r'^simple', 'simple example')
<_sre.SRE_Match object; span=(0, 6), match='simple'>

$:匹配输入字符串的结束位置(匹配的字符串只能在字符串的结束位置)

>>> re.search(r'simple$', 'simple example')

>>> re.search(r'simple$', 'This example is simple')
<_sre.SRE_Match object; span=(16, 22), match='simple'>

>>> re.search(r'simple$', 'Thisexampleissimple')
<_sre.SRE_Match object; span=(13, 19), match='simple'>

\ :①将一个普通字符变成特殊字符,例如\d表示匹配所有十进制数字

②解除元字符的特殊功能,例如 \. 表示匹配点号本身

③引用序号对应的子组(小括号括起来的)所匹配的字符串:当在反斜杠\后加的是数字时,如果数字是1~99,表示引用序号对应的值所匹配的字符串。如果数字是0或者三位的数字,则是一个八进制数,表示这个八进制数对应的ASCII码对应的字符。

前两个在我的上一篇博客有介绍,下面是第三个的例子:

>>> re.search(r'(easy)\1', 'Take it easy')
>>> re.search(r'(easy)\1', 'easy-going')
>>> re.search(r'(easy)\1', 'easy')                       #这个为啥匹配不上一开始很不理解


>>> re.search(r'(easy)\1', 'easyeasy')
<_sre.SRE_Match object; span=(0, 8), match='easyeasy'>   #r'(easy)\1'相当于 r'easyeasy',下文有详解

#即使是'easyeasyeasy'匹配的还是'easyeasy',这里一开始也很不理解


#16进制的30对应的是ASCII码的数字0,16进制下的30对应8进制的60
#运行里输入calc打开计算器,查看里选择程序员可以查看进制转换
>>> re.search(r'(easy)\060', 'easyeasy')
>>> re.search(r'(easy)\060', 'easy0')
<_sre.SRE_Match object; span=(0, 5), match='easy0'>

>>> re.search(r'(easy)\060', 'easyeasy0')
<_sre.SRE_Match object; span=(4, 9), match='easy0'>

#10进制的97对应小写字母a,10进制的97对应的八进制是141
>>> re.search(r'(easy)\141', 'easyeasya')
<_sre.SRE_Match object; span=(4, 9), match='easya'>


[...]:字符类,匹配所包含的的任意一个字符。这里字符类就是一个字符集合的意思,被它包含在里面的元字符都会失去其特殊功能。

注一:连字符 - 如果出现在字符串中间表示字符范围描述;如果出现在首位则仅作为普通字符

注二:特殊字符出现在字符类中时,特殊字符仅有反斜杠\保持特殊含义,用于转义字符,其它特殊字符如*、+、?等均作为普通字符

注三:脱字符^如果出现在首位则表示匹配不包含其中的任意字符;如果出现在字符串中间就仅作为普通字符匹配

>>> re.search(r'.', 'easyeasya')          #若果说是一个点的话,则匹配任意除换行符之外的字符
<_sre.SRE_Match object; span=(0, 1), match='e'>

>>> re.search(r'\.', 'easy.easy')         #如果说是\ + . 那就只是匹配一个点
<_sre.SRE_Match object; span=(4, 5), match='.'>

>>> re.search(r'[.]', 'easy.easy')        #和\+.是一个道理
<_sre.SRE_Match object; span=(4, 5), match='.'>



#字符类的意思是将它里面的内容当做普通的字符来看待,除了几个特殊的字符-、\、^
>>> re.findall(r'[a-z]', 'Example')      #findall方法是找到所有匹配的字符,将他们打包成一个列表返回
['x', 'a', 'm', 'p', 'l', 'e']

>>> re.findall(r'[\n]', 'Example\n')     #匹配回车
['\n']

>>> re.findall(r'[^a-z]', 'Example\n')   #放在字符类最前面表示:除了字符类里面的内容,其他的都匹配。相当于取反
['E', '\n']

>>> re.findall(r'[a-z^]', 'Example\n^')  #放在后面的时候只是匹配脱字符字符串本身
['x', 'a', 'm', 'p', 'l', 'e', '^']

{M,N} M和N均为非负整数,其中M <= N,表示前边的正则表达式匹配[M, N](左闭右闭区间)次

注一:{M,}表示至少匹配M次

注二:{,N}等价于{0,N}

注三:{N}表示需要匹配N次

温馨提醒:逗号 , 后别习惯性的加了空格。不能有空格!不能有空格!不能有空格!(重要的事说三遍)

>>> re.search(r'play{3}', 'playyyyyyyy')     #注意是重复匹配y三次,而不是匹配play三次
<_sre.SRE_Match object; span=(0, 6), match='playyy'>

>>> re.search(r'(play){3}', 'playplayplay')  #想要重复匹配play三次,可以加上小括号()
<_sre.SRE_Match object; span=(0, 12), match='playplayplay'>

>>> re.search(r'(play){1,5}', 'playplayplay')
<_sre.SRE_Match object; span=(0, 12), match='playplayplay'>

* 表示匹配前面的子表达式零次或多次,等价于{0,}

+表示匹配前面的子表达式一次或多次,等价于{1,}

?表示匹配前面的子表达式零次或一次,等价于{0,1}

条件一样时,建议使用上面三个特殊字符。这样不仅更加简洁,而且正则表达式内部对这三个字符做了优化,所以用这三个字符更高效。



贪婪和非贪婪:

关于重复操作,我们有一点要注意,正则表达式默认启用了贪婪模式进行匹配。

贪婪就是贪心,只要在符合的条件下,它会尽可能多的去匹配。

>>> s = "<html><title>www.baidu.com</title></html>"

>>> re.search(r'<.+>', s)  #想要匹配<html>这样写的话能不能找到呢。 .表示消耗掉一些字符,html总共有四个所以用+,遇到>停下来
<_sre.SRE_Match object; span=(0, 41), match='<html><title>www.baidu.com</title></html>'>
#结果却把整个都找到了
#这就是贪婪

既然是这样,我们必须使用非贪婪模式才可以。

启用非贪婪的模式:在表示重复的元字符后面加上一个?就可以了。

这时?就不代表匹配零次或一次,而是表示启用非贪婪模式。

>>> re.search(r'<.+?>', s)   # +表示将.重复,所以在+后加上?
<_sre.SRE_Match object; span=(0, 6), match='<html>'>


>>> re.search(r'(love){1,4}', 'lovelovelovelovelovelove')
<_sre.SRE_Match object; span=(0, 16), match='lovelovelovelove'>
#匹配1次到4次,因为是贪婪模式,所以匹配了四次


>>> re.search(r'(love){1,4}?', 'lovelovelovelovelovelove')
<_sre.SRE_Match object; span=(0, 4), match='love'>
#启用非贪婪模式,只匹配了一次


学习了以上的知识,个人对 \ + 数字的用法不太明白。百度也看不太明白,就扒了扒官文,找到了这样几句话:

ps. 扒官文的过程:打开IDLE的官文,搜re,我选的是第四个,就是re (class in typing) 的下一个(module)



第一句话的意思是: 匹配同一数字对应的子组的内容。(感觉怪怪的)


发现了这个:

https://zhidao.baidu.com/question/981985866163210579.html?qbl=relate_question_0&word=%5C1...%5C9%20%C6%A5%C5%E4%B5%DAn%B8%F6%B7%D6%D7%E9%B5%C4%D7%D3%B1%ED%B4%EF%CA%BD

里面说:

\1表示重复正则第一个圆括号内匹配到的内容
\2表示重复正则第二个圆括号内匹配到的内容

比如有以下正则:
([a-z])([a-z])\2\1
则可以匹配字符串abba
第一个圆括号内的正则匹配字符a,则在字符串最后\1这个位置必须是字符a,第二个括号匹配字符b,在倒数第二个位置\2必须是字符b
如果有嵌套的圆括号,顺序是按左括号的次序计算的


再仔细阅读了一下小甲鱼发的详解,感觉这里的重点是在“引用”这两个字上

自己经过多轮尝试,试出了几个成功的,对这个引用二字有了一点点深入的理解:

>>> re.search(r'(5)(4)\1\2', '5454')
<_sre.SRE_Match object; span=(0, 4), match='5454'>
>>> re.search(r'(5)(4)\1\2', '54354')
>>> re.search(r'(5)(4)\1', '5555')
>>> re.search(r'(5)(4)\1', '5555444')
>>> re.search(r'(5)(4)\1', '55554')
>>> re.search(r'(5)(4)\1', '5555454')
<_sre.SRE_Match object; span=(3, 6), match='545'>


反正我是从这里猜想出 r'(5)(4)\1\2' == r'(5)(4)(5)(4)'  即\1引用了(5),\2引用了(4)

也就是re.search(r'(5)(4)\1\2', '5454') 等价于re.search(r'(5)(4)(5)(4)', '5454')

也就是重复匹配的意思,只不过换成了字组。再回头看看,还是自己想复杂了。



想要获取更多关于正则表达式特殊符号的信息:http://bbs.fishc.com/thread-57691-1-1.html

附:要5鱼币的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值