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()