1.模块的功能:
- 为了方便管理程序,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用。
- 在Python中有许多模块,我们可以导入模块来提高自己的编程效率,也能够更好地实现程序的功能。
2.正则
正则是描述一类字符或者字符串的规则,嵌套在re模块中,如果导入re模块就是使用正则取匹配字符或字符串中的内容。
2.1 字符组
字符组:[] 写在中括号中的内容都可以出现在字符串中
[0-9] 匹配数字
[a-z] 匹配小写字母 ASCII码97-122
[A-Z] 匹配大写字母 ASCII码65-90
[a-zA-Z] 匹配大小写字母
[a-zA-Z0-9] 匹配大小写字母+数字
[a-zA-Z0-9_] 匹配数字字母下划线
2.2 元字符
- \w 匹配数字字母下划线
- \d 匹配所有的数字
- \s 匹配所有的空白符 回车/制表符
- \t 匹配一个制表符
- \n 匹配回车
- \W 匹配非字母数字下划线
- \D 匹配非数字
- \S 匹配非空白/回车/制表符
- [\s\S]、[\d\D]、[\w\W]匹配所有的字符
- ^ 匹配一个字符串的开始
- $ 匹配一个字符串的结尾
- .匹配除换行符以外的所有字符
- [^]匹配非字符组内容,例如[^a]就是匹配字符串中不是a的内容
- 有一些有特殊意义的元字符进入字符组会回复它本来的意义:. | [] () / ? -(在字符组中有特殊意义,需要转义)
- a|b 或 符合a规则或者b规则的都可以匹配,如果a规则是b规则的一部分,且a规则比b规则更长,应当将a规则写在前面,将更复杂,更长的规则写在前面。
2.3 量词
- {n}表示这个量词之前的字符出现n次
- {n,}表示这个量词之前的字符至少出现n次
- {n, m}表示这个量词之前的字符出现n-m次
- ?表示匹配量词之前的字符出现0次或者1次 表示可有可无
- +表示匹配量词之前的字符出现 1次或者多次
- *表示匹配量词之前的字符出现0次或者多次
2.4 分组
- 对于正则表达式而言,有时候我们需要进行分组,来整体约束某一字符出现的次数,如(\.[\w+])?
2.5 正则练习
1 匹配整数 \d+
2 匹配小数 \d+\.\d+
3 匹配整数或者小数 \d+(\.\d+)?
4 匹配身份证号码:[1-9]\d{16}[\dx]|[1-9]\d{14}
5 匹配年月日 :^[1-9]\d{0,3}-(1[0-2]|0?[1-9])-(3[01]|[12]\d|0?[1-9])$
6 匹配QQ号: [1-9]\d{4-11}
7 11位电话号码:1[3-9]\d{9}
8 匹配验证码:[\da-zA-Z]{4}
9 匹配邮箱:[0-9a-zA-Z][\w\-.]+@[a-zA-Z.0-9\-]+(\.[a-zA-Z0-9\-]+)*\.[a-zA-Z0-9]{2,6}
10 匹配内层没有小括号的表达式:\([^()]\)
2.6 正则表达式的特点
正则表达式的匹配特点:贪婪匹配
- 贪婪匹配会在允许的范围内取最长的结果
- 非贪婪模式/惰性匹配:在量词的后面加上?即在范围内尽量少的匹配。
3.re模块
3.1 re模块功能之查找(使用模块前必须import re导入模块)
# findall ret = re.findall('\d+', 'sjkdfa112shfa998') print(ret) # 结果:['112', '998']
# search ret = re.search('\d+', 'sjkdfa112shfa998') if ret: # 这里的ret只是正则结果的内存地址 print(ret.group()) # 通过ret.group()获取真正的结果 # 结果:['1', '1', '2', '9', '9', '8']
# match 从头开始匹配,相当于search中的正则表达式加上一个^ ret = re.match('\d', '122sjkdfashfa998') print(ret) # 结果:112
3.2 切分
s = 'adkf12fag34'
ret = re.split('\d+',s)
print(ret)
# 结果:['adkf', 'fag', '']
3.3 替换
1 # sub
2 ret = re.sub('\d+', 'H', 'alex83taibai40', 1)
3 print(ret)
4 # 结果:alexHtaibai40
# subn 返回一个元组,第二个元素是替换的次数
ret = re.subn('\d+', 'H', 'alex83taibai40')
print(ret)
# 结果:('alexHtaibaiH', 2)
3.4 编译
compile 节省使用正则表达式解决问题的时间,将正则表达式编译成字节码,在多次使用时不会多次编译。
1 ret = re.compile('\d+') 2 res = ret.findall('alex83taibai40') 3 res_1 = ret.findall('213afda324') 4 res_2 =ret.search('4343faag') 5 print(res, res_1, res_2)
3.5 finditer
# finditer 节省使用正则表达式解决问题的空间 ret = re.finditer('\d+', 'alex342fa5') print(ret) for i in ret: print(i.group())
4.分组在re模块中的使用
4.1 优先匹配分组中的内容
1 import re
2 s = '<a>wahaha</a>'
3 ret = re.search('<(\w+)>(\w+)</(\w+)>',s)
4 print(ret.group()) # 括号内默认为0,打印所有的结果
5 print(ret.group(1)) # 数字参数代表的是取对应分组中的内容
6 print(ret.group(2))
7 print(ret.group(3))
8 # 结果:
9 <a>wahaha</a>
10 a
11 wahaha
12 a
4.2 findall中的分组优先:优先显示分组中的内容:
1 import re
2 ret = re.findall('\d+(\.\d+)?', '1.234*4.3')
3 print(ret)
4 # 结果:['.234', '.3']
findall中的分组优先:优先显示分组中的内容
1 import re 2 ret = re.findall('\d+(?:\.\d+)?', '1.234*4.3') 3 print(ret) 4 # 结果:['1.234', '4.3']
4.3 split中的分组
1 import re 2 s = 'adkf12fag34' 3 ret = re.split('\d+',s) 4 print(ret) 5 6 s = 'adkf12fag34' 7 ret = re.split('(\d+)',s) 8 print(ret) 9 10 # 结果: 11 ['adkf', 'fag', ''] 12 ['adkf', '12', 'fag', '34', '']
4.4 分组的命名
1 import re 2 s = '<a>wahaha</a>' 3 ret = re.search('>(?P<con>\w+)<',s) 4 print(ret.group(1)) 5 print(ret.group('con')) 6 # 结果: 7 wahaha 8 wahaha
1 s = '<a>wahaha</b>' 2 pattern = '<(\w+)>(\w+)</(\w+)>' 3 ret = re.search(pattern, s) 4 print(ret.group(1) == ret.group(3)) 5 # 结果:False
注:使用前面的分组,要求使用这个名字的分组和前面同名分组中的内容匹配的必须一致。
1 s = '<a>wahaha</b>' 2 pattern = '<(?P<tab>\w+)>(\w+)</(?P=tab)>' 3 ret = re.search(pattern, s) 4 print(ret)
4.5 正则的表达应该更精确
1 ret = re.findall(r"\d+", "1-2*(60+(-40.35/5)-(-4*3))") 2 print(ret) # 结果将不应该匹配的小数也匹配出来了 3 # 结果:['1', '2', '60', '40', '35', '5', '4', '3'] 4 5 # 应该精确取到整数 6 ret = re.findall(r"\d+\.\d+|\d+", "1-2*(60+(-40.35/5)-(-4*3))") 7 print(ret) 8 # 结果:['1', '2', '60', '40.35', '5', '4', '3'] 9 10 # 使用分组优先显示整数 11 ret = re.findall(r"\d+\.\d+|(\d+)", "1-2*(60+(-40.35/5)-(-4*3))") 12 ret.remove('') 13 print(ret) 14 # 结果:['1', '2', '60', '5', '4', '3']