菜鸟学习Python(第十期)~~正则表达式(三)
继续上一次正则表达式学习~~
点击下面蓝色字体可回看往期知识点:
Python(第十期)~~正则表达式(一)
Python(第十期)~~正则表达式(二)
回顾:
正则表达式是以字符串的形式来描述的,而且表达式的强大之处在于特殊符号的应用。
值得关注的是,点号(.)在正则表达式中表示匹配时除了 换行符之外的任何字符,它就是一个特殊的字符。正是这些特殊符号,使得一个正则表达式可以匹配一个复杂的规则,而不仅仅是匹配一个字符串。特别地,如果你只需要匹配一个字符串,那用 find() 方法就可以了。
由于特殊符号 前面已经提到过,因此这里就自行去查看:
下面引入特殊字符:
特殊符号是由两部分组成的,一部分是 元字符。此外,所有的元字符包括:
. ^ $ * + ? { } [ ] \ | ( )
而另一部分则则是 反斜杠 \ 加上普通符号 * 组成的特殊符号,它拥有特殊的含义。
13、元字符
(1)、点号(.):除了换行符之外的任何字符都基本可以匹配。
(2)、竖线 | :类似逻辑关系中的或,学过C语言的同学们都知道,这就是按位或的意思。例如,A|B就 表示匹配正则表达式 A或者B的形式。
>>> import re
>>> re.search(r"Love(E|F)", "LoveE")
<re.Match object; span=(0, 5), match='LoveE'>
>>> re.search(r"Love(L|O)","I Love YOU")
>>> re.search(r"Love(L|O)","I LoveL YOU")
<re.Match object; span=(2, 7), match='LoveL'>
>>> re.search(r"Love(e|O)","I Love YOU")
>>> re.search(r"Lov(e|O)","I Love YOU")
<re.Match object; span=(2, 6), match='Love'>
(3)、托字符(^):定位匹配,匹配字符串的开始位置(即确定一个位置)。
>>> re.search(r"^love", "love you, Python")
<re.Match object; span=(0, 4), match='love'>
>>> re.search(r"^日本", "日本 you, Python")
<re.Match object; span=(0, 2), match='日本'>
>>> re.search(r"^2019", "2019的欧洲, LOVE")
<re.Match object; span=(0, 4), match='2019'>
>>> re.search(r"^2", "2019的欧洲, LOVE")
<re.Match object; span=(0, 1), match='2'>
>>> re.search(r"^2019的欧洲", "2019的欧洲, LOVE")
<re.Match object; span=(0, 7), match='2019的欧洲'>
(4)、美元符号($):匹配输入字符串的结束位置
>>> re.search(r"LOVE$", "2019的欧洲, LOVE")
<re.Match object; span=(9, 13), match='LOVE'>
>>> re.search(r"2019的欧洲$", "love, 2019的欧洲")
<re.Match object; span=(6, 13), match='2019的欧洲'>
(5)、反斜杠 \ (再细说用法)
接下来的元字符是最困难、最复杂的 反斜杠(),反斜杠在正则表达式中应用是最广泛的,它既可以将一个普通的字符变为特殊字符(这部分内容下节课继续讲解),也可以解除元字符的特殊功能,这些在前面已经提到过。
特别地 . 匹配的就不是除换行符之外的任何字符了,他匹配的就是一个点(.)。
如果在反斜杠 \ 后面加的是数字,那么有两种表示方案:
①、如果跟着的数字是 1~99,就表示引用序号对应的值组所匹配的字符串,其中序号所对应的值组:为 \ 前面的值组,\ 序号必须在对应的值组的正后面,序号为第几个值组。 为了方便理解请看下面的例子:
>>> re.search(r"(you)\1", "I love youyou")
<re.Match object; span=(7, 13), match='youyou'>
>>> re.search(r"(欧洲)\1", "you from 欧洲欧洲")
<re.Match object; span=(9, 13), match='欧洲欧洲'>
>>> re.search(r"(love)\1(you)", "I loveloveyouyou")
<re.Match object; span=(2, 13), match='loveloveyou'>
>>> re.search(r"(love)(you)\2", "I loveloveyouyou")
<re.Match object; span=(6, 16), match='loveyouyou'>
>>> re.search(r"(love)\1(you)\2", "I loveloveyouyou")
<re.Match object; span=(2, 16), match='loveloveyouyou'>
>>> re.search(r"(欧洲)\1(英国)\2", "二战时期的 欧洲欧洲英国英国")
<re.Match object; span=(6, 14), match='欧洲欧洲英国英国'>
源码剖析:
上面的(you)是第一个值组(序号是从1开始计算的,因为0表示一个八进制数),所以 \1,且\1 表示you,其实 r’(you)\1’ 就等于 ‘youyou’。
其中值组就是用小括号括起来的一个整体,与数学中的括号是一样的,把一个东西当做一个整体,那么就把它括起来。
>>> re.search(r"(I )love(英国)\2", "I love英国英国.com")
<re.Match object; span=(0, 10), match='I love英国英国'>
>>> re.search(r"(you )love(英国)\2", "you love英国英国.com")
<re.Match object; span=(0, 12), match='you love英国英国'>
>>> re.search(r"(you )love(英国)\2", "you love英国英国")
<re.Match object; span=(0, 12), match='you love英国英国'>
>>> re.search(r"(I )love(you)\2", "I loveyouyou.com")
<re.Match object; span=(0, 12), match='I loveyouyou'>
②、如果随后紧跟的数字是 0 或者 3位的数字,那么它是一个八进制数,表示的是这个八进制数对应的 的是ASCII 码对应的字符。
回顾一下进制转换的数学逻辑:
(a)
(b)
(c)
例如:字符 0 对应的十进制数为 48,对应的八进制数为 60,这里要三位数,就是060
所以:
>>> import re
>>> re.search(r"\060", '0')
<re.Match object; span=(0, 1), match='0'>
>>> re.search(r"I love love\060", 'I love love0')
<re.Match object; span=(0, 12), match='I love love0'>
(6)、中括号([ ]),作用是生成一个字符类。
其实字符类就是一个字符集合的意思,此外,值的注意的是:被中括号包含在里面的元字符都会失去特殊功能,这与就反斜杠加上一个元字符是类似的,举例:
>>> import re
>>> re.search(r"[.]", 'I love you.com')
<re.Match object; span=(10, 11), match='.'>
>>> re.search(r"[u.]", 'I love you.com')
<re.Match object; span=(9, 10), match='u'>
>>> re.search(r"[.u]", 'I love you.com')
<re.Match object; span=(9, 10), match='u'>
字符类的意思就是将自身里面的内容都当做普通的字符看待,除了几个特殊的字符:
比如:
①、小横杠(-),我们用它表示范围,在前面讲过,此次讲一讲其他方法:re.findall(),在Python解释器中按F1打开文档
大致含义:
对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。
(也可访问线上中文文档:https://docs.python.org/zh-cn/3/library/re.html?highlight=findall#re.findall
)
在 3.7 版更改: 非空匹配现在可以在前一个空匹配之后出现了。
特别地,findall 和 search 相比,似乎更符合我们的需求,但是当遇到值组时,findall 也会有陷阱,后期会升入补充这部分知识点。
②、反斜杠( \ ),把反斜杠放在字符类[ ]中,它不表示本身,因为这样会报错, 反斜杠在字符类里,表示的是Python 字符串的转义符。
在字符串里,我们都知道 \n 表示回车换行的意思,由此我们有:
>>> re.findall(r"[\n]","12a32\nbc43jf3")
['\n']
>>> re.findall(r"[\n]","12a3\nbc243jf3")
['\n']
>>> re.findall(r"[\n]","12a3 \n bc243jf3")
['\n']
③托字符 ^,在字符类[ ]里,表示‘除了’(取反)的意思,但是要注意的是,这个托字符 ^ 必须放在最前面:
>>> re.findall(r"[^a-z]","250e1314bc1997fh2019")
['2', '5', '0', '1', '3', '1', '4', '1', '9', '9', '7', '2', '0', '1', '9']
如果放在后面,就是表示匹配它本身了。
特别地,这里说明一种元字符重复元字符,大括号{ },如{i,j}(要求i,j均为非负整数,且i<=j)表示前面的内容匹配 i~j次。
>>> re.search(r'Pythox{3}', 'I love Pythoxxx')
<_sre.SRE_Match object; span=(7, 15), match='Pythoxxx'>
>>> re.search(r'(you){3}', 'I love youyouyou')
<re.Match object; span=(7, 16), match='youyouyou'>
每日三道题, 笔试不吃亏
题目10:古典问题(斐波拉契数列):
有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?
x1 = 1
x2 = 1
for i in range(1,22):
print('%12ld %12ld' % (x1,x2))
if (i % 3) == 0:
print(end='')
x1 = x1 + x2
x2 = x1 + x2
执行结果:
题目11:判断101-200之间有多少个素数,并输出所有素数。
程序分析:判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,则表明此数不是素数,反之是素数。
h = 0
leap = 1
from math import sqrt
from sys import stdout
for m in range(520,1314):
k = int(sqrt(m + 1))
for i in range(2,k + 1):
if m % i == 0:
leap = 0
break
if leap == 1:
print(end='%-4d' % m)
h += 1
if h % 10 == 0:
print(end='')
leap = 1
print('素数个数为%d个' % h)
执行结果:
题目12:打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身。例如:153是一个"水仙花数",并且153=1 ^3 + 5^3 + 3^3。
M = ""
for a in range(1,10):
for b in range(10):
for c in range(10):
num = a*100+b*10+c
if a**3+b**3+c**3 == num:
print(M,end='')
print(num,end=' ')
M=","
执行结果:
153 ,370 ,371 ,407
或者
for i in range(100,1000):
s=str(i)
one=int(s[-1])
ten=int(s[-2])
hun=int(s[-3])
if i == one**3+ten**3+hun**3:
print(i)
执行结果:
扫码关注我,一起交流学习