学了很久的python基础,感觉自己的基础较牢固了,最近便开始学习《Python核心编程第三版》这本书。认真阅读了这本书第一章,发现这本书写得真的特别好,详细得当,但是遗憾的是感觉中文有些地方仍然翻译得不是很完美。当然,以我这半吊子的水平,我是不会去看什么英文版的啦。
写下这篇博客一方面是为了记录学习笔记,另方面也是为了加深博主自己对正则表达式的理解。
一、常见的正则表达式表
以下的表是博主自己按照书一个个写的,又加上了字符串示例与匹配结果,方便理解。若发现表中的失误地方,望朋友们指出错误,让我得以及时纠正。
在此提示一下,表中的匹配结果,博主是用python的re模块中的search"搜素"函数测试的,若是用模块中的match“匹配”函数,有些结果将会不一样。
表中的有些没有写出字符串示例与匹配结果,是因为该正则表示法有些复杂,后面将会进行补充说明。
二、re模块常见函数和方法
compile | 参数是正则表达式,返回一个正则表达式对象。 |
match、search、findall、finditer | 这四个都是通过正则表达式来匹配字符串,但返回的形式不一样。 |
sub、subn | 使用定义的字符串,替代正则表达式下所有能匹配出来的字符串。subn功能与sub 一样,但还能返回替换的个数。 |
split | 既有同字符串的split方法一样的功能,也能通过正则表达式来分割字符串。 |
group、groups | 返回匹配对象,各有区别。 |
groupdict | 返回一个包含所有匹配的命名子组的字典。 |
常用的模块属性
re.I、re.IGNORECASE | 不区分大小写的匹配。 |
re.L、re.LOCALE | 根据所使用的本地语言环境通过\w、\W、\b、\B、\s、\S实现匹配。 |
re.M、re.MULTILINE | ^和$分别匹配目标字符串所在行的起始和结尾,而不是严格匹配整个字符串本身的起始和结尾。 |
re.S、re.DOTALL | 该标记表示"."能够匹配全部字符(包括\n)。 |
re.X、re.VERBOSE | 正则表达式中的#号被视为注释,没有斜线转义的空白符将被忽视。 |
函数的简单讲解
函数:search、match
区别:
两个都是返回一个匹配出的对象。
search 可以从字符串的任意位置进行匹配。
match 从字符串的头开始进行匹配。即若是一开始就错则匹配不成功。
函数:findall、finditer
区别:
两个都是返回匹配出的 所有 符合要求的对象。
findall返回列表,finditer则是返回一个迭代器。
方法: group、groups
区别:
两者关系类似与一个是子集,一个是真子集。
group返回一个值,可以返回匹配对象和子组。
groups返回一个元组,只含有一个子组。
三、扩展表达式法
(1)(?:...)表示法
import re
m = re.search(r'(\w*)://(?:\w|\s)*.(\w*).\w*/', 'https://www .baidu.com/')
if m is not None:
print(m.group())
print(m.groups())
else:
print('None')
输出结果:
https://www .baidu.com/
('https', 'baidu')
讲解:
例 ae*中*只对e其特殊作用,而(ae)*中*对ae其到作用。“()”表示法起到与算法里的括号类似作用。
而(?:....)表示法也起到这样作用。但是从输出结果('https', 'baidu')可以看出,()把匹配结果存入了子组中,用groups可以展现出来,而(?:...)则没有把...内容存入子组中。
(2)(?<name>...)表示法
import re
m = re.search(r'(?P<head>\w*)://(?:\w|\s)*.(?P<body>\w*).\w*/', 'https://www .baidu.com/')
if m is not None:
print(m.group())
print(m.groupdict())
else:
print('None')
输出结果:
https://www .baidu.com/
{'head': 'https', 'body': 'baidu'}
讲解:
把匹配的字符串存入字典中<name>中name作键,匹配的字符串作值。也可以用groups输出子组。
(3)(?=name)表示法
import re
m = re.search(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?P<number>\d{4}) (?P=areacode)-(?P=prefix)-(?P=number)', '(800) 555-1212 800-555-1212')
if m is not None:
print(m.group())
else:
print('None')
输出结果
(800) 555-1212 800-555-1212
讲解:
该表示法是重复使用(?P<name>...)表示法匹配出来的字符串。
即代码里的(?P<areacode>...)匹配出了字符串800,后面的(?P=areacode)可以用800来替换。
(4)(?(id/name)Y|N)表示法
>>> bool(re.search(r'(?:(x)|y)(?(1)y|x)', 'xy'))
True
>>> bool(re.search(r'(?:(x)|y)(?(1)y|x)', 'xx'))
False
讲解:
该正则表达式是为了找xy或则yx字符串。
re.search(r'(?:(x)|y)(?(1)y|x)', 'xy')
这段中,(?:(x)|y)匹配到了x,故而把'x'加入子组中,(?(1)y|x)指当1号子组存在时,匹配y字符,否则匹配x字符,故而能成功匹配xy。
若是给出的字符串是yx,则(?:(x)|y)表示'y'成功匹配,但不加入子组,此时无子组。(?(1)y|x)取'x'字符进行匹配。
(5)(?iLmsux)表示法
去看上面 re模块常见函数和方法里的常用模块属性,(?i)、(?L)、(?m)、(?s)、(?x)作用与之一样。
这里就略过代码讲解。
四、补充
贪婪与非贪婪匹配
例:给出字符串'abcdAefgAhijkA'
若是给出匹配的正则表达式为 \w*A 则匹配出来的结果是abcdAefgAhijkA。
若是给出匹配的正则表达式为 \w*?A 则匹配出来的结果是abcdA。
前者贪婪匹配,后则非贪婪匹配。
非贪婪匹配是指,当匹配到刚好满足条件为止。而贪婪匹配则是不满足一个正好匹配的结果,匹配还会进行下去。