Python核心编程 课后习题
第一部分 正则表达式
1-1 识别后续的字符串:“bat”、“bit”、“but”、“hat”、“hit”或者“hut”
In [3]:
import re
data = 'bat sad bit ad but d fa hat adfad hit ad da d hut aa'
patt = '[bh][uia]t'
m = re.findall(patt,data)
print(m)
1-2 匹配由单个空格分隔的任意单词对,也就是姓和名。
In [75]:
data = 'adfass323f sadfa aadfa'
patt = '\w+\s\w+'
m = re.match(patt, data)
m.group()
Out[75]:
1-3 匹配由单个逗号和单个空白符分隔的任何单词和单个字母,如姓氏的首字母。
In [82]:
data = 'adfaf aa, dadada'
patt = '\w+,\s\w+'
m = re.search(patt, data)
m.group()
Out[82]:
1-4 匹配所有有效 Python 标识符的集合。
In [108]:
data = 'adaas1212dfdfsadfaaf_'
patt = '[_A-Za-z]+[_\w]+' #有效Python标识符:以下划线和字母开头的非空字符,
m = re.match(patt, data)
m.group()
Out[108]:
1-5 根据读者当地的格式,匹配街道地址(使你的正则表达式足够通用,来匹配任意数量的街道单词,包括类型名称)。例如,美国街道地址使用如下格式:1180 Bordeaux Drive。使你的正则表达式足够灵活,以支持多单词的街道名称,如 3120 De la Cruz Boulevard。
In [119]:
data = '3120 De la Cruz Bou levard'
patt = r'\d+.+' #以数字开头的任何字符串
m = re.match(patt,data)
m.group()
Out[119]:
1-6 匹配以“www”起始且以“.com”结尾的简单Web 域名;例如,www://www. yahoo.com/。选做题:你的正则表达式也可以支持其他高级域名,如.edu、.net 等(例如,http://www.foothill.edu)。
In [236]:
data = 'http://www.y.as.sadf.a121.2asasdoo.cc'
patt = r'http://(www\.[\w|\.]+\.(com|cn|org|net|cc))'
m = re.match(patt,data)
m.group(1)
Out[236]:
1-7 匹配所有能够表示 Python 整数的字符串集。
In [262]:
data = '-123141234'
patt = '[-|+]?\d+$'
m = re.match(patt, data)
m.group()
Out[262]:
1-8 匹配所有能够表示 Python 长整数的字符串集。
In [264]:
data = '123141234L'
patt = '[-|+]?\d+[lL]'
m = re.match(patt, data)
m.group()
Out[264]:
1-9 匹配所有能够表示 Python 浮点数的字符串集。
In [272]:
data = '-12310.09'
patt = '[-|+]?\d+\.\d*'
m = re.match(patt, data)
m.group()
Out[272]:
1-10 匹配所有能够表示 Python 复数的字符串集。
In [277]:
data = '121+989i'
patt = r'\d+(\+\d*i)' #简单的实部和虚部都是整数
m = re.match(patt, data)
m.group()
Out[277]:
1-11 匹配所有能够表示有效电子邮件地址的集合(从一个宽松的正则表达式开始,然后尝试使它尽可能严谨,不过要保持正确的功能)。
In [75]:
data = 'y.1-a-9.a@t.w-0.9-3-c.com'
patt = r'[a-zA-Z]+([-\.]?\w+)+@((\w+-?\w*)+\.)+\w{2,3}' #6~18个字符,可使用字母、数字、下划线,需以字母开头
m = re.match(patt, data)
m.group()
Out[75]:
1-12 匹配所有能够表示有效的网站地址的集合(URL) (从一个宽松的正则表达式开始,然后尝试使它尽可能严谨,不过要保持正确的功能)。
In [93]:
data = 'http://www.ba-i.du.com.cn http://ww.qq.com'
patt = r'http://((\w+[-\.])*\w+)'
m = re.match(patt, data).group()
n = re.findall(patt, data)
print(n)
1-13 type()。内置函数 type()返回一个类型对象,如下所示,
该对象将表示为一个 Pythonic类型的字符串。
>>> type(0)
<type 'int'>
>>> type(.34)
<type 'float'>
>>> type(dir)
<type 'builtin_function_or_method'>
创建一个能够从字符串中提取实际类型名称的正则表达式。函数将对类似于<type'int' >的字符串返回 int(其他类型也是如此,如 'float' 、'builtin_function_or_method' 等)。
注意:你所实现的值将存入类和一些内置类型的__name__属性中。
In [104]:
data = type(.34)
print(data)
type(0)
Out[104]:
In [125]:
import re
data = "type 'int' type 'float'"
patt = r'type \'(\w+)\''
m = re.findall(patt, data)
m
Out[125]:
1-14 处理日期。1.2 节提供了来匹配单个或者两个数字字符串的正则表达式模式,来表示1~9 的月份(0?[1-9])。创建一个正则表达式来表示标准日历中剩余三个月的数字。
In [118]:
date = '10 11 12 09'
patt = '1\d'
m = re.findall(patt,date)
m
Out[118]:
1-15 处理信用卡号码。1.2 节还提供了一个能够匹配信用卡(CC)号码([0-9]{15,16})的正则表达式模式。然而,该模式不允许使用连字符来分割数字块。创建一个允许使用连字符的正则表达式,但是仅能用于正确的位置。例如,15 位的信用卡号码使用 4-6-5 的模式,表明 4 个数字-连字符-6 个数字-连字符-5 个数字;16 位的信用卡号码使用 4-4-4-4 的模式。记住,要对整个字符串进行合适的分组。选做题:有一个判断信用卡号码是否有效的标准算法。编写一些代码,这些代码不但能够识别具有正确格式的号码,而且能够识别有效的信用卡号码。
In [137]:
data = '1111-111111-11111'
data2 = '1111-1111-1111-1111'
patt = r'\d{4}-\d{4}(\d{2})?-\d{4}\d?(-\d{4})?'
m = re.match(patt, data)
m.group()
Out[137]:
In [12]:
import re
data = '1111-111111-11111'
data2 = '1111-1111-1111-1111'
patt = r'\d{4}-(\d{4}(\d{2})?)-(\d{4}\d?)(-\d{4})?'
m = re.match(patt, data2)
if m == None:
print('Error')
elif len(m.group(1))==6 and len(m.group(3))==5:
print('Yes, It is 465')
elif len(m.group(1))==4 and len(m.group(3))==4:
print('Yes, it is 4444')
else:
print('No')
In [30]:
#!/usr/bin/env python
#gendata.py
from random import randrange, choice
from string import ascii_lowercase as lc
#from sys import int
from time import ctime
tlds = ('com', 'edu', 'net', 'org', 'gov')
for i in range(randrange(5,11)):
dtint = randrange(2**32) #pick date
dtstr = ctime(dtint) #date string
llen = randrange(4, 8) #login is shorter
login = ''.join(choice(lc) for j in range(llen))
dlen = randrange(llen, 13) #domain is longer
dom = ''.join(choice(lc) for j in range(dlen))
print('%s::%s@%s.%s::%d-%d-%d' % (dtstr, login,
dom, choice(tlds), dtint, llen, dlen))
1-16 为 gendata.py 更新代码,使数据直接输出到 redata.txt 而不是屏幕。
In [28]:
#!/usr/bin/env python
#gendata.py
from random import randrange, choice
from string import ascii_lowercase as lc
#from sys import int
from time import ctime
tlds = ('com', 'edu', 'net', 'org', 'gov')
f = open('redata.txt','w')
for i in range(randrange(5,11)):
dtint = randrange(2**32) #pick date
dtstr = ctime(dtint) #date string
llen = randrange(4, 8) #login is shorter
login = ''.join(choice(lc) for j in range(llen))
dlen = randrange(llen, 13) #domain is longer
dom = ''.join(choice(lc) for j in range(dlen))
data = '%s::%s@%s.%s::%d-%d-%d\n' % (dtstr, login,
dom, choice(tlds), dtint, llen, dlen)
f.write(data)
print('%s::%s@%s.%s::%d-%d-%d' % (dtstr, login,
dom, choice(tlds), dtint, llen, dlen))
f.close()
1-17 判断在redata.txt中一周的每一天出现的次数(换句话说,读者也可以计算所选择的年份中每个月中出现的次数)。
In [48]:
#Fweekday = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
import re
patt = r'^\w{3}\s'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
In [50]:
import re
patt = r'\s\w{3}\s'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
1-18 通过确认整数字段中的第一个整数匹配在每个输出行起始部分的时间戳,确保在redata.txt 中没有数据损坏。
In [3]:
import re
patt = r'^\w{3}\s\w{3}\s\s?\d{1,2}\s\d{2}:\d{2}:\d{2}'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
创建以下正则表达式。1-19 提取每行中完整的时间戳。
In [4]:
import re
patt = r'^\w{3}\s\w{3}\s\s?\d{1,2}\s\d{2}:\d{2}:\d{2}'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
1-20 提取每行中完整的电子邮件地址。
In [7]:
import re
patt = r'\w+@\w+\.\w{3}'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
1-21 仅仅提取时间戳中的月份。
In [9]:
import re
patt = r'\s\w{3}\s'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
1-22 仅仅提取时间戳中的年份。
In [12]:
import re
patt = r'(\d{4}):'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
1-23 仅仅提取时间戳中的时间(HH:MM:SS)。
In [24]:
import re
patt = r'\d{2}:\d{2}:\d{2}'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
1-24 仅仅从电子邮件地址中提取登录名和域名(包括主域名和高级域名一起提取)。
In [15]:
import re
patt = r'@(\w+\.\w{3})'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
1-25 仅仅从电子邮件地址中提取登录名和域名(包括主域名和高级域名)。
In [17]:
import re
patt = r'@(\w+)\.(\w{3})'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()
1-26 使用你的电子邮件地址替换每一行数据中的电子邮件地址。
In [31]:
import re
patt = r'\w+@\w+\.\w{3}'
f = open('redata.txt','r')
for i in f:
#print(i)
l = re.sub(patt,'xx@yy.com',i)
print(l)
f.close()
1-27 从时间戳中提取月、日和年,然后以“月,日,年”的格式,每一行仅仅迭代一次。
In [35]:
import re
patt = r'(\w{3})\s\s?(\d{1,2})\s\d{2}:\d{2}:\d{2}\s(\d{4})'
f = open('redata.txt','r')
for i in f:
print(re.findall(patt, i.rstrip()))
f.close()