您的位置:首页 > 编程语言 > Python开发

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

2018-02-08 15:37 537 查看
在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.searc
bb2b
h(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鱼币的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: