菜鸟学习Python(第十期)~~正则表达式(二)
继续上一次正则表达式(一)学习~~
Python(第十期)~~正则表达式(一)
回顾一段代码:
>>> import re
>>> re.search(r'YOU.', 'I LOVE YOU')
>>> re.search(r'YOU.', 'I LOVE YOU.')
<re.Match object; span=(7, 11), match='YOU.'>
>>> re.search(r'YOU.', 'I LOVE YOU')
>>> re.search(r'I.', 'I LOVE YOU')
<re.Match object; span=(0, 2), match='I '>
>>> re.search(r'YOU.', 'I LOVE YOU ')
<re.Match object; span=(7, 11), match='YOU '>
>>>
10、反斜杠“\”
想要消除一个字符串的特殊功能,就在前面加上 反斜杠(\), 当然,反斜杠也带来特殊字符串的一些功能。
>>> re.search(r'.', 'I LOVE YOU. ')
<re.Match object; span=(0, 1), match='I'>
>>> re.search(r'\.', 'I LOVE YOU. ')
<re.Match object; span=(10, 11), match='.'>
这里 ‘.’ 匹配的就是 点号(.)本身了,这时候,点号.不代表任何其他字符,它只代表点号,前面的反斜杠已经将其解译了。
也就是说,在正则表达式中,反斜杠同样具有剥夺元字符的特殊功能的能力.(什么是元字符后面会讲到)。
值得注意的是,反斜杠 \ 还可以使得普通的字符具有特殊能力,它能匹配数字(暗示了可以匹配IP地址,换句话说有数字的基本都能匹配),在学习Python经常使用\d就是为了匹配数字,其实\d就是正则表达式的一部分。下面使用 ‘\d’ 来匹配任何数字(只举几例),如:
(1)数字:
>>> re.search(r'\d.', 'I LOVE YOU 1314. ')
<re.Match object; span=(11, 13), match='13'>
>>> re.search(r'\d\d.', 'I LOVE YOU 1314. ')
<re.Match object; span=(11, 14), match='131'>
>>> re.search(r'\d\d\d.', 'I LOVE YOU 1314. ')
<re.Match object; span=(11, 15), match='1314'>
(2)IP地址
可以打开这个网站一键获取自己正在使用的IP地址
http://www.whatismyip.com.tw/
https://whoer.net/zh
点击进入如
下面是我开始匹配IP地址
>>> re.search(r'\d\d\d.\d\d\d.\d\d\d.\d\d\d', '103.16.26.148')
>>> re.search(r'\d\d\d.\d\d.\d\d.\d\d\d', '103.16.26.148')
<re.Match object; span=(0, 13), match='103.16.26.148'>
>>> re.search(r'\d\d\d\.\d\d\d\.\d\d\d\.\d\d\d', '192.168.111.123')
<re.Match object; span=(0, 15), match='192.168.111.123'>
首先,\d 表示匹配的数字是 0~9,但是 ip 地址的约定范围每组数字的范围是 0~255,那你这里 \d\d\d 最大匹配数字是 999 ,而 ip 地址的最大范围是 255;然后,你这里要求 ip 地址每组必须是三位数字,但实际上有些 ip 地址中的某组数字只有 1 位或者 2 位,像这种情况,我们就匹配不了了,
所以要做适当的 \d 数量的调整。
当然也还有其他解决办法,下面给出字符类:
11、字符类
表示一个字符串的范围,需要创建一个叫做 字符类 的东西,使用中括号[ ] 来创建一个字符类,字符类的含义就是你只要匹配字符类中的一个字符,那么就匹配成功了,如:
(1)匹配 元音字母(aeiou)
>>> re.search(r'[aeiou]', 'i love you')
<re.Match object; span=(0, 1), match='i'>
>>> re.search(r'[aeiou]', 'I love YOU')
<re.Match object; span=(3, 4), match='o'>
>>> re.search(r'[aeiou]', 'I LOVe YOU')
<re.Match object; span=(5, 6), match='e'>
>>> re.search(r'[aeiou]', 'I LOVE YOu')
<re.Match object; span=(9, 10), match='u'>
值得注意的是,元音字母的匹配不能匹配大写的,严格按照英语的元音写法来进行匹配。这是因为正则表达式 是默认开启 大小字母敏感 模式的,所以 大写 ‘I’ 和小写 ‘i’ 会区分开来。解决的方案有两种,一种是关闭大小写敏感模式(后边进行讲解),另一种是修改我们的字符类[aeiou]为[aeiouAEIOU]。
如果修改大小模式则可以匹配:
>>> re.search(r'[aeiouAEIOU]', 'I LOVE YOu')
<re.Match object; span=(0, 1), match='I'>
>>> re.search(r'[AEIOU]', 'I LOVE YOu')
<re.Match object; span=(0, 1), match='I'>
>>> re.search(r'[AEIOU]', 'i LOVE YOu')
<re.Match object; span=(3, 4), match='O'>
(2)表示一个范围
可以在字符类中使用 横杆或减号 ‘-’ 表示一个范围,如:
(2.1)字母范围
>>> re.search(r'[a-z]', 'i LOVE YOU')
<re.Match object; span=(0, 1), match='i'>
>>> re.search(r'[A-Z]', 'i LOVE YOU')
<re.Match object; span=(2, 3), match='L'>
>>> re.search(r'[A-Z]', 'i love You')
<re.Match object; span=(7, 8), match='Y'>
(2.2)数值范围
>>> re.search(r'[1-5]', 'i love You 1314')
<re.Match object; span=(11, 12), match='1'>
>>> re.search(r'[4-5]', 'i love You 1314')
<re.Match object; span=(14, 15), match='4'>
>>> re.search(r'[3-4]', 'i love You 1314')
<re.Match object; span=(12, 13), match='3'>
12 、匹配次数
限定重复匹配的次数,我们可以使用 大括号 来解决,举例:
>>> re.search(r'BCD{3}E', 'BCDDDE')
<re.Match object; span=(0, 6), match='BCDDDE'>
>>> re.search(r'ab{3}c', 'abbbc')
<re.Match object; span=(0, 5), match='abbbc'>
其中 {3} 就表示前面的 D或b匹配时要重复3次,即BCDDDE和abbbc。
值得注意的是,大括号里还可以给出重复匹配次数的范围,例如{a, b} 表示匹配 a 到 b 次。
>>> re.search(r'ab{2,10}c', 'abbc')
<re.Match object; span=(0, 4), match='abbc'>
>>> re.search(r'BCD{2,10}E', 'BBCDDDE')
<re.Match object; span=(1, 7), match='BCDDDE'>
匹配 0~255:
使用正则表达式来匹配 0~255
>>> re.search(r'[0-255]', '134')
<re.Match object; span=(0, 1), match='1'>
但是我们想匹配 的是134 ,结果只是匹配到了 1。
解释:
切记:正则表达式 匹配的是字符串,所以呢,数字对于字符来说,只有 0~9,例如 134,就是由1、3、4 这三个字符来组成的,并没有说个 十百千 这些单位。因此,[0-255] 这个字符类(其中0-2,指的是 0 1 2,后面两个 5 就重复了)表示的是[0125]这四个数字其中的某一个,由此 re.search(r'[0-255]', '134') 就只匹配到了一个 1。
下面解决这个问题,应该这么写:
re.search('[01]\d\d|2[0-4]\d|25[0-5]', '134')
<re.Match object; span=(0, 3), match='134'>
源码剖析:
这里匹配的正则表达式就是 [01]\d\d 或者 2[0-4]\d 或者 25[0-5],可以发现其中任何一个都是成立的。这里的 “或 ” 和 C语言中的 “或” 是一样用意的。
不过,需要知道是上面的写法还是存在问题,要求匹配的数字必须是 3 位的,类似的我们可以输入如下匹配内容会发现无法匹配:
>>> re.search('[01]\d\d|2[0-4]\d|25[0-5]', '4')
>>> re.search('[01]\d\d|2[0-4]\d|25[0-5]', '1')
>>> #None空的
>>> re.search('[01]\d\d|2[0-4]\d|25[0-5]', '13')
>>>
因此下面可以这样改写,让前面的两位数可以重复 0 次(因为默认是重复1次嘛):
>>> re.search('[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '1')
<re.Match object; span=(0, 1), match='1'>
>>> re.search('[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '13')
<re.Match object; span=(0, 2), match='13'>
>>> re.search('[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '134')
<re.Match object; span=(0, 3), match='134'>
因此,我们就可以来匹配一个 IP 地址啦:
>>> re.search('(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '192.168.42.1')
<re.Match object; span=(0, 12), match='192.168.42.1'>
>>> re.search('(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}[01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]', '103.16.26.148')
<re.Match object; span=(0, 13), match='103.16.26.148'>
源码剖析:
上面的小括号的意思就是分组,首先 ([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]) 作为一个组,然后加上 点号,(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5]).) 作为新的组,然后这个组重复3次,最后再加一组数字。这样就完成了一对 ip 地址的匹配啦。
每日三道题, 笔试不吃亏:
题目7:如何将一个列表的数据复制到另一个列表中?
程序分析:使用列表[ : ], 事实上就是一种赋值的行为。
>>> a = [1314, 520, 3.1415926]
>>> b = a[:]
>>> print(b)
[1314, 520, 3.1415926]
题目8:输出 九九 乘法口诀表。
程序分析:分别对行和列考虑,共9行9列,i设为控制行,j设为控制列。
for i in range(1, 10):
for j in range(1, i+1):
print("%d*%d=%-3d"%(i, j, i*j), end=" ")
print("第%d行:"%i)
执行结果:
1*1=1 第1行:
2*1=2 2*2=4 第2行:
3*1=3 3*2=6 3*3=9 第3行:
4*1=4 4*2=8 4*3=12 4*4=16 第4行:
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 第5行:
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 第6行:
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 第7行:
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 第8行:
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 第9行:
题目9:暂停一秒输出。
程序分析:使用 time 模块的 sleep() 函数
import time
dict1 = {1998: '值得纪念的日子', 2019: '70周年'}
for key, value in dict.items(dict1):
print(key, value)
time.sleep(2) # 暂停 2 秒
执行结果:
1998 值得纪念的日子
2019 70周年
>>>
补充题:暂停一秒输出,并格式化当前时间。
import time
#使用年月日语法
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
# 暂停2秒
time.sleep(2)
print("格式化当前时间:", time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
执行结果:
2019-10-01 23:30:02
格式化当前时间: 2019-10-01 23:30:04
>>>