写在前面:前段时间,陆陆续续的学了好几遍正则表达式,但是都没有吃透,感觉像没学到什么一样。每次使用的时候还得不断的百度。这次我又来重新学一下,争取吃透。同时,我又想到了我上学时候凸显出来的一个弊端:不懂的东西我就不管了,也不会去想要知道答案什么的,学习态度很不好。现在越来越意识到这样下去不行。不懂的一定要网上查阅各种资料,一定要将不懂的弄懂。是时候好好学点东西了。
《正则表达式》
节选自leon《用Python学习正则表达式》,
原文地址:http://daydayup.is-programmer.com/posts/1200.html
正则表达式手册:http://tool.oschina.net/uploads/apidocs/jquery/regexp.html
我觉得作者写得很好,我看完之后竟然看懂了,感谢原作者。所以我就分享一下。
对我自己,有几个要注意的点:
>>>p = re.compile(r’[-a-c]’)
>>>m = p.search(‘b-a.exe’)
>>>(0,1)
在这里“[ ]”里面代表的是几个字符中的任意一个。就算一个字符串里面有好几个,只选择最先出现的那一个。只有一个,一个。在这里就是“-,a,b,c”。不要把它看成是顺序,一定要“-a”开头的那种。不要想当然。
还有就是那种比较长的正则表达式,看起来有点乱。
>>>p = re.compile(r'(\b\w+)\s+\1')
# 这句话是啥意思,根本看不懂。
# 我懂了。
# (\b\w+)代表一个单词;\s+代表若干空格;\1代表第一个分组,也就是(\b\w+)。
>>>m = p.search(‘Paris in the thespring’).group()
>>>‘the the’
还有就是,()代表分组或者某一部分重复才使用括号。
上次看的时候,一般的符号和特殊字符都没什么问题,主要是这个扩展表示法有点不太懂。这次来探个究竟。
非记录分组和命名分组
若一个表达式很复杂,有很多分组,而每个分组都要记录的话就比较困难。
Python有自己的扩展,就是在括号后面紧跟一个P,即‘(?P<name>...)’,表示Python的扩展。如(?P<name>…)定义了一个命名分组,而(?P=name)则表示对前面的向后引用(与\1的功能一样)。
(?P<name>...)和(?P=name)
(?P<name>...)用来定义一个命名分组,可以通过MatchObject的方法group(‘name’)得到,同时在表达式中,也可以用(?P=name)来表示对它的引用。
它的命名分组就是指最前面的‘Lots’部分,后面的‘Lots’只是对前面的引用,并不是‘word’分组的一部分。
(?=...)
称为零宽度正预测先行断言。它断言自身出现的位置后面能匹配表达式,但不包括这些表达式。比如‘\b\w+(?=ing)\b’,匹配ing结尾的单词的前面部分。
(?<=...)
与前面类似,也是用于指定位置,不做实际匹配,叫零宽度正回顾后发断言。它断言自身出现的位置前面能匹配表达式。比如(?<=\bre) \w+\b,表示以re开头的单词的后面部分。
(?!...)
零宽度负预测先行断言。断言此位置的后面不能匹配表达式。比如,\d{3}(?!\d)匹配三位数字后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
(?<!...)
零宽度负回顾后发断言。断言此位置的前面不能匹配表达式。比如(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。
(?:...)
表示非记录分组。即这个分组不会被记录下来。
>>> m = re.match(“([abc])+”, “abc”)
>>> m.groups()
(‘c’, )
>>> m = re.match(“(?:[abc])+”, “abc”)
>>> m.groups()
()