正则表达式、贪婪匹配与非贪婪匹配、re模块
今日内容学习总结
通过上周的学习,我们对于模块的运用有了一个了解,这周开始我们以一个正则表达式开始进行学习。
正则表达式简介
正则表达式,是一门独特的语言,专门用来匹配,校验,筛查所需的数据。同时正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。它可以利用一些特殊符号的组合去字符串中筛选出想要的数据。所以我们学习正则表达式,很大程度上就是学习一些特殊符号的使用。
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。re 模块使 Python 语言拥有全部的正则表达式功能。这里我们用一个案例来实现正则表达式:
# 有些网站获取手机号会有很多校验规则,我们通过代码实现这些功能
# 1.获取用户的手机号
phone_num = input('请输入您的手机号>>>:').strip()
# 2.先校验是否是11位
if len(phone_num) == 11:
# 3.再校验是否是纯数字
if phone_num.isdigit():
# 4.校验开头是否合法
if phone_num.startswith('13') or phone_num.startswith('15') or phone_num.startswith(
'17') or phone_num.startswith('18'):
print('是一个正确的手机号')
else:
print('手机号开头不合法')
else:
print('手机号必须是纯数字')
else:
print('手机号必须是11位')
上述代码我们通过不断的if是实现了这个校验的效果,现在我们看看如果通过正则表达式实现会怎么样:
# 正则表达式实现手机校验功能
import re
phone_number = input('请输入你的手机号: ').strip()
if re.match('^(13|14|15|18)[0-9]{9}$', phone_number):
print('是正确的手机号码')
else:
print('手机号码格式不正确')
我们发现,正则表达式也是一个简化代码,提高代码效率的功能。而我们使用正则表达式,是因为典型的搜索和替换操作要求您提供与预期的搜索结果匹配的确切文本。虽然这种技术对于对静态文本执行简单搜索和替换任务可能已经足够了,但它缺乏灵活性,若采用这种方法搜索动态文本,即使不是不可能,至少也会变得很困难。但是正则表达式拥有一下三个优点:1.测试字符串内的模式。2.替换文本。3.基于模式匹配从字符串中提取子字符串。
在匹配筛选查找数据的时候可以使用正则提供的符号也可以直接写目标数据。
正则表达式之字符组
| 实例 | 描述 |
|---|---|
| [Pp]ython | 匹配 "Python" 或 "python" |
| rub[ye] | 匹配 "ruby" 或 "rube" |
| [aeiou] | 匹配中括号内的任意一个字母 |
| [0-9] | 匹配任何数字。类似于 [0123456789] |
| [a-z] | 匹配任何小写字母 |
| [A-Z] | 匹配任何大写字母 |
| [a-zA-Z0-9] | 匹配任何字母及数字(顺序可变如[A-Z0-9a-z]) |
| [^aeiou] | 除了aeiou字母以外的所有字符 |
| [^0-9] | 匹配除了数字外的字符 |
正则表达式之特殊字符
| 实例 | 描述 |
|---|---|
| . | 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 |
| \d | 匹配一个数字字符。等价于 [0-9]。 |
| \D | 匹配一个非数字字符。等价于 [^0-9]。 |
| $ | 匹配字符串的结尾 |
| \S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
| \w | 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
| \W | 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
| ^ | 匹配字符串的开头 |
| \n, \t, 等. | 匹配一个换行符。匹配一个制表符。等 |
| () | 给正则表达式分组 不影响正则匹配 |
| [] | 字符组的概念(里面所有的数据都是或的关系) |
| [^] | 上箭号出现在了中括号的里面意思是取反操作 |
正则表达式之量词
| 实例 | 描述 |
|---|---|
| * | 重复零次或者多次(默认就是多次:越多越好) |
| + | 重复一次或者多次(默认就是多次:越多越好) |
| ? | 重复零次或者一次(默认就是一次:越多越好) |
| 重复n次 | |
| 重复最少n次最多多次(越多越好) | |
| 重复n到m次(越多越好) |
复杂的正则编写
很多常见的正则校验符号,不需要我们编写,直接百度查找即可。代码示例:
# 校验用户身份证号码15位或者17位
^[1-9][0-9]{14} # 校验15位
^[1-9][0-9]{16}[0-9x] # 校验17位,同时末位可能是数字或x
取消转义
\n \n False
\\n \n True
\\\\n \\n True
# 在python中还可以在字符串的前面加r取消转义
贪婪匹配与非贪婪匹配
贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。代码示例:
<.*> <script>alert(123)<script> # 1条
<.*?> <script>alert(123)<script> # 2条
re 模块
在python中无法直接使用正则,需要借助于模块。而借助的模块就是re模块。re模块是python独有的匹配字符串的模块,该模块中提供的很多功能是基于正则表达式实现的。
常用方法
1.re.compile(pattern,flags = 0 )
将正则表达式模式编译为正则表达式对象,可使用match(),search()以及下面所述的其他方法将其用于匹配
import re
a = re.compile('\d{2}')
print(a.search('12abc')) # <_sre.SRE_Match object; span=(0, 2), match='12'>
print(a.search('12abc').group()) # 12 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
2、re.search(pattern,string,flags = 0 )
扫描字符串以查找正则表达式模式产生匹配项的第一个位置 ,然后返回相应的match对象。None如果字符串中没有位置与模式匹配,则返回;否则返回false。请注意,这与在字符串中的某个点找到零长度匹配不同。
import re
# 在这个字符串进行匹配,只会匹配一个对象
print(re.search('\w+', 'abcde').group()) # abcde
print(re.search('a', 'abcde').group()) # a
3、re.match(pattern,string,flags = 0 )
如果字符串开头的零个或多个字符与正则表达式模式匹配,则返回相应的匹配对象。None如果字符串与模式不匹配,则返回;否则返回false。请注意,这与零长度匹配不同。
import re
# 同search,不过在字符串开始处进行匹配,只会匹配一个对象
print(re.match('\w+', 'abc123de').group()) # abc123de
print(re.match('a', 'abcde').group()) # a
print(re.match('\D+', 'abc123de').group()) # abc
4、re.fullmatch(pattern,string,flags = 0 )
如果整个字符串与正则表达式模式匹配,则返回相应的match对象。None如果字符串与模式不匹配,则返回;否则返回false。请注意,这与零长度匹配不同。
import re
print(re.fullmatch('\w+', 'abcde').group()) # abcde
print(re.fullmatch('abcde', 'abcde').group()) # abcde
5、re.split(pattern,string,maxsplit = 0,flags = 0 )
通过出现模式来拆分字符串。如果在pattern中使用了捕获括号,那么模式中所有组的文本也将作为结果列表的一部分返回。如果maxsplit不为零,则最多会发生maxsplit分割,并将字符串的其余部分作为列表的最后一个元素返回。
import re
print(re.split('[ab]', 'abcde')) # ['', '', 'cde'] 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(re.split(r'\W+', 'Words, words, words.')) # ['Words', 'words', 'words', '']
print(re.split(r'(\W+)', 'Words, words, words.', 1)) # ['Words', ', ', 'words, words.']
print(re.split(r'(\W+)', 'Words, words, words.')) # ['Words', ', ', 'words', ', ', 'words', '.', '']
print(re.split('[a-f]+', '0a3d9g1d', flags=re.IGNORECASE)) # ['0', '3', '9g1', '']
6、re.findall(pattern,string,flags = 0 )
以string列表形式返回string中pattern的所有非重叠匹配项。从左到右扫描该字符串,并以找到的顺序返回匹配项。如果该模式中存在一个或多个组,则返回一个组列表;否则,返回一个列表。如果模式包含多个组,则这将是一个元组列表。空匹配项包含在结果中。
import re
pprint(re.findall('a', 'This is a beautiful place!')) # ['a', 'a', 'a']
7、re.finditer(pattern,string,flags = 0 )
返回一个迭代器,该迭代器在string类型的RE 模式的所有非重叠匹配中产生匹配对象。 从左到右扫描该字符串,并以找到的顺序返回匹配项。空匹配项包含在结果中。
import re
print(re.finditer('[ab]', 'This is a beautiful place!')) # <callable_iterator object at 0x000001E6AA03E278> 迭代器对象
res = re.finditer('[ab]', 'This is a beautiful place!')
print(next(res).group()) # a
res_list = [i.group() for i in res]
print(res_list) # ['b', 'a', 'a']
8、re.sub(pattern,repl,string,count = 0,flags = 0 )
返回通过用替换repl替换字符串中最左边的不重叠模式所获得的字符串。如果找不到该模式, 则返回的字符串不变。 repl可以是字符串或函数;如果是字符串,则处理其中的任何反斜杠转义。即,将其转换为单个换行符,将其转换为回车,依此类推。count参数表示将匹配到的内容进行替换的次数
import re
print(re.sub('\d', 's', 'abc12jh45li78', 2)) # abcssjh45li78 将匹配到的数字替换成S,替换2个 不写2默认情况是将匹配到所有的数字替换成S
9、re.subn(pattern,repl,string,count = 0,flags = 0 )
执行与相同的操作sub(),但返回一个元组。(new_string, number_of_subs_made)
import re
print(re.subn('\d', 's', 'abc12jh45li78', 3)) # ('abcssjhs5li78', 3)
10、re.escape(pattern)
escape中的所有字符图案,除了ASCII字母,数字和'_'。如果要匹配可能包含正则表达式元字符的任意文字字符串。
import re
print(re.escape('python.exe\n')) # python\.exe\
11、search()与match()方法
Python提供了两种基于正则表达式的原始操作: re.match()仅在字符串的开头匹配,re.search()检查匹配项,在字符串中的任何位置检查匹配项(这是Perl的默认设置)。
import re
print(re.match("c", "abcdef")) # None
print(re.search("c", "abcdef")) # <_sre.SRE_Match object; span=(2, 3), match='c'>
# 以开头的正则表达式'^'可用于search()限制字符串开头的匹配项
print(re.match("c", "abcdef")) # None
print(re.match("^c", "abcdef")) # None
print(re.match("^a", "abcdef")) # <_sre.SRE_Match object; span=(0, 1), match='a'>
今日作业
# 使用正则筛选出网站的数据
import re
import requests
res = requests.get(url='http://www.redbull.com.cn/about/branch')
with(open('a.txt', 'wb')) as res_write:
for i in res:
res_write.write(i)
res1 = re.compile('data-describe=\'(.*?)\'><h2>(.*?)</h2><p class=\'mapIco\'>(.*?)</p><p class=\'mailIco\'>(.*?)</p><p class=\'telIco\'>(.*?)</p></li>')
with(open('a.txt', 'r', encoding='utf8')) as res_read:
txt = res_read.read()
res1_read = res1.findall(txt)
print(res1_read) # 打印出来是一个列表套元组
for i in res1_read:
print("""
-----------------
公司名称:{}
地址:{}
邮编:{}
电话:{}
-----------------
""".format(i[1], i[2], i[3], i[4])) # 循环取列表中的元组的对应索引值

学习内容总结
浙公网安备 33010602011771号