AI人工智能与数学之美人工智能微刊人工智能(语言识别&图像识别)

菜鸟学习Python(第十期)~~正则表达式(二)

2019-10-01  本文已影响0人  KangSmit的算法那些事儿

继续上一次正则表达式(一)学习~~
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
>>> 
上一篇下一篇

猜你喜欢

热点阅读