Python程式設計
Lesson 13: 正規表達式(Regular Expression)
字串基本功能
字串(str)資料型態
字串: 2個「單引號」或「雙引號」之間的字元符號資料
x1 = "這是字串資料型態的範例"
x2 = '使用單引號的字串'
x3 = '123' # 雖是數字, 但用單引號框起來,故也是字串
x4 = "This is Mary's house." #字串包含了單引號, 故用雙引號框起來
x5 = '小明說:"這是我的書。"' # 字串如包含雙引號, 則用單引號框起來
字串中「單引號」或「雙引號」的處理方式
加號'+'可用來「串接」兩個以上的字串
x1 = "字串1"
x2 = '字串2'
x3 = x1 + x2 # 串接, 存入另一個變數
print(x3)
print(x1 + x2) # 也可直接執行「串接」運算
x4 = '詞彙'
x5 = '頻率'
x6 = x4 + "," + x5 # 多個字串串接
print(x6)
字串超過1行:使用3個「單引號」或「雙引號」框起來
字串太長,超過一行以上怎麼辦?
使用3個「單引號」或「雙引號」框起來
# 字串內容太長,超過一行
x1 = """清晨進入一個曲折像蛇般的峽灣中,兩邊都是陸地,
上午8點見到了英國國旗在一個小山的山頂上揚起。
很快的,船之就進入到一個較為寬廣的水域,
四周被小山圍繞著。同時在兩邊高崗上,
層層羅列著房舍,終於到達香港。
回到艙房中,感謝上帝的照顧以及美善。
登岸,遇到艾德博士,他問我「你是馬偕嗎?」"""
逸出字元:以「反斜線」'\'開頭的特殊字元
特殊字元需加上「反斜線」才能正常使用
str1 = '千山鳥飛絕 萬徑人蹤滅' # 同一行
str2 = '千山鳥飛絕\n萬徑人蹤滅' # 加上換行字元\n
str3 = '千山鳥飛絕\t萬徑人蹤滅' # 加上Tab字元\t
str4 = 'This is John\'s pen.' # 單引號,雙引號的「逸出字元」的寫法
字串強制轉換函式:str()
str() 可將數值資料轉換為字串
score = int(input('輸入分數:'))
str1 = '你輸入的分數是' + score # 錯誤:字串, 整數無法相加
str2 = '你輸入的分數是' + str(score) # 正確:字串相加
print(str2)
變數名稱請勿命名為str, 會將str()函式名稱遮住
words = ['學堂', '醫館', '講道']
counts = [123, 456, 145]
for i in range(len(words)):
str1 = words[i] + ',' + str(counts[i]) # 3個字串串接
print(str1)
字串的索引值
字串也有個索引值,可取得字串內個別字元
str1 = '千山鳥飛絕'
print(str1[3]) # 印出'飛'
for i in range(len(str1)):
print(str1[i]) # 逐行印出str1內容
字串索引值: 以方括弧指定, 由0算起
str2 = '千山鳥飛絕 萬徑人蹤滅'
print('字串第1~3個字元', str2[0:3]) # 索引值0開始,2結束
print('字串第2~4個字元', str2[1:4]) # 索引值1開始,3結束
print('字串第2個字元到最後', str2[1:]) # 索引值1開始,到最後結束
print('字串第3,5,7字元', str2[2:7:2]) # 索引值2開始,6結束,每隔2取值
指定索引值範圍:取得部份字串內容
[開始值:結束值:間隔]
poem = '''
首先,它創造了峻潔清冷的藝術境界。單就詩的字面來看,
“孤舟蓑笠翁”一句似乎是作者描繪的重心,占據了畫面的主體地位。
這位漁翁身披蓑笠獨自坐在小舟上垂綸長釣。
“孤”與“獨”二字已經顯示出他的遠離塵世,甚至揭示出他清高脫俗、
兀傲不群的個性特征。作者所要表現的主題于此已然透出,
但是作者還嫌意興不足,又為漁翁精心創造了一個廣袤無垠、
萬籟俱寂的藝術背景:遠處峰巒聳立,萬徑縱橫,然而山無鳥飛,徑無人蹤。
往日沸騰喧鬧,處處生機盎然的自然界因何這般死寂呢?一場大雪紛紛揚揚。
'''
plist = []
index = poem.find('。') # 尋找下一個句點的位置
while index != -1: # 有找到句點
print(index)
plist.append(poem[0:index]) # 儲存斷句:0開始,index值結束(不含句點)
poem = poem[index+1:] # 更新poem: 只留下句點之後剩餘的文字
index = poem.find('。') # 尋找下一個句點的位置
print(plist)
範例:利用索引值斷句
找出這段文字共有幾個句子
str2 = '千山鳥飛絕 萬徑人蹤滅'
for i in range(len(str2)):
print('第%d個字元是%c' % (i+1, str2[i]))
len(): 字串長度
取得字串長度的函式: len()
第1個字元是千
第2個字元是山
第3個字元是鳥
第4個字元是飛
第5個字元是絕
第6個字元是
第7個字元是萬
第8個字元是徑
第9個字元是人
第10個字元是蹤
第11個字元是滅
執行結果
poem = '''
首先,它創造了峻潔清冷的藝術境界。單就詩的字面來看,
“孤舟蓑笠翁”一句似乎是作者描繪的重心,占據了畫面的主體地位。
這位漁翁身披蓑笠獨自坐在小舟上垂綸長釣。
“孤”與“獨”二字已經顯示出他的遠離塵世,甚至揭示出他清高脫俗、
兀傲不群的個性特征。作者所要表現的主題于此已然透出,
但是作者還嫌意興不足,又為漁翁精心創造了一個廣袤無垠、
萬籟俱寂的藝術背景:遠處峰巒聳立,萬徑縱橫,然而山無鳥飛,徑無人蹤。
往日沸騰喧鬧,處處生機盎然的自然界因何這般死寂呢?一場大雪紛紛揚揚。
'''
plist = poem.split('。')
print(plist)
找出這段文字共有幾個句子
拆分字串的函式: split()
['\n首先,它創造了峻潔清冷的藝術境界', '單就詩的字面來看,\n“孤舟蓑笠翁”一句似乎是作者描繪的重心,占據了畫面的主體地位', '\n這位漁翁身披蓑笠獨自坐在小舟上垂綸長釣', '\n“孤”與“獨”二字已經顯示出他的遠離塵世,甚至揭示
出他清高脫俗、\n兀傲不群的個性特征', '作者所要表現的主題于此已然透出,\n但是作者還嫌意興不足,又為漁翁精心創造了一個廣袤無垠、\n萬籟俱寂的藝術背景:遠處峰巒聳立,萬徑縱橫,然而山無鳥飛,徑無人蹤', '\n往日沸騰喧鬧,處處生
機盎然的自然界因何這般死寂呢?一場大雪紛紛揚揚', '\n']
執行結果
str2 = '千山鳥飛絕 萬徑人蹤滅'
word = input('輸入要查詢的字串:')
if word in str2:
print('輸入的文字在字串中')
else:
print('輸入的文字不在字串中')
以in運算子查詢字串內容
輸入要查詢的字串:飛
輸入的文字在字串中
輸入要查詢的字串:海
輸入的文字不在字串中
執行結果
正規表達式
Regular Expression
功能:模式比對與搜尋
def taiwanPhoneNum(string):
"""檢查是否有含手機聯絡資訊的台灣手機號碼格式"""
if len(string) != 12: # 如果長度不是12
return False # 傳回非手機號碼格式
for i in range(0, 4): # 如果前4個字出現非數字字元
if string[i].isdecimal() == False:
return False # 傳回非手機號碼格式
if string[4] != '-': # 如果不是'-'字元
return False # 傳回非手機號碼格式
for i in range(5, 8): # 如果中間3個字出現非數字字元
if string[i].isdecimal() == False:
return False # 傳回非手機號碼格
if string[8] != '-': # 如果不是'-'字元
return False # 傳回非手機號碼格式
for i in range(9, 12): # 如果最後3個字出現非數字字元
if string[i].isdecimal() == False:
return False # 傳回非手機號碼格
return True # 通過以上測試
print("a123456789: 是台灣手機號碼", taiwanPhoneNum('a123456789'))
print("0932-999-199: 是台灣手機號碼", taiwanPhoneNum('0932-999-199'))
如何比對手機號碼格式?
def taiwanPhoneNum(string):
if len(string) != 12: # 如果長度不是12
return False # 傳回非手機號碼格式
for i in range(0, 4): # 如果前4個字出現非數字字元
if string[i].isdecimal() == False:
return False # 傳回非手機號碼格式
if string[4] != '-': # 如果不是'-'字元
return False # 傳回非手機號碼格式
for i in range(5, 8): # 如果中間3個字出現非數字字元
if string[i].isdecimal() == False:
return False # 傳回非手機號碼格
if string[8] != '-': # 如果不是'-'字元
return False # 傳回非手機號碼格式
for i in range(9, 12): # 如果最後3個字出現非數字字元
if string[i].isdecimal() == False:
return False # 傳回非手機號碼格
return True # 通過以上測試
def parseString(string):
"""解析字串是否含有電話號碼"""
notFoundSignal = True # 註記沒有找到電話號碼為True
for i in range(len(string)): # 用迴圈逐步抽取12個字元做測試
msg = string[i:i+12]
if taiwanPhoneNum(msg):
print("電話號碼是: %s" % msg)
notFoundSignal = False
if notFoundSignal: # 如果沒有找到電話號碼則列印
print("%s 字串不含電話號碼" % string)
msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '請明天13:00請到牛津藝術中心參加策展茶會'
msg3 = '請明天13:00請到牛津藝術中心參加策展茶會, 可用0933-080-080聯絡我'
parseString(msg1)
parseString(msg2)
parseString(msg3)
如何從訊息中擷取出手機號碼?
正規表達式是一種「文字模式」的表達方法
xxxx-xxx-xxx
其中,'\d' 表示0-9的數字字元
'\d\d\d\d-\d\d\d-\d\d\d'
以手機號碼為例:
格式表達方式
'\\d\\d\\d\\d-\\d\\d\\d-\\d\\d\\d'
Python字串中的'\'必須用「逸出字元」'\\'
r'\d\d\d\d-\d\d\d-\d\d\d'
或是在字串前加r:防止逸出字元被轉譯
正規表達式位於re模組,使用時要先建立Regex物件
❶使用re.compile()建立Regex物件
import re
...
手機規則 = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d')
...
❷呼叫Regex物件的search()搜尋想要比對的對象
import re
字串 = '請明天13:00請到牛津藝術中心參加策展茶會, 可用0933-080-080聯絡我'
手機規則 = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d')
比對結果 = 手機規則.search(字串)
if (比對結果 == None):
print('找不到')
else:
print(比對結果.group())
比對結果 = 手機規則.search(字串)
回傳None 或 MatchObject物件
import re
def parseString(string):
"""解析字串是否含有電話號碼"""
手機規則 = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d')
比對結果 = 手機規則.search(string)
if 比對結果 != None: # 檢查比對結果
print("電話號碼是: %s" % 比對結果.group())
else:
print("%s 字串不含電話號碼" % string)
msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '請明天13:00請到牛津藝術中心參加策展茶會'
msg3 = '請明天13:00請到牛津藝術中心參加策展茶會, 可用0933-080-080聯絡我'
parseString(msg1)
parseString(msg2)
parseString(msg3)
以正規表達式改寫手機號碼比對的範例
import re
def parseAllString(string):
"""解析字串中所有的電話號碼"""
手機規則 = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d')
比對結果串列 = 手機規則.findall(string)
return 比對結果串列
msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '請明天13:00請到牛津藝術中心參加策展茶會'
msg3 = '請明天13:00請到牛津藝術中心參加策展茶會, 可用0933-080-080聯絡我'
print(parseAllString(msg1))
print(parseAllString(msg2))
print(parseAllString(msg3))
Regex物件的比對方法: search()與findall()
search(): 第一個比對相符的位置
findall(): 所有比對相符的字串串列
re.compile(比對規則)如何處理重複出現的字元?
import re
...
手機規則 = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d')
...
規則:4個\d-3個\d-3個\d
\d重複出現,可用\d{重複次數}取代
import re
...
手機規則 = re.compile(r'\d{4}-\d{3}-\d{3}')
...
更多比對模式範例
xx-xxxxxxxx
'\d\d-\d\d\d\d\d\d\d\d'
以市話為例:
格式表達方式
02-26212121
r'\d{2}-\d{8}'
import re
...
市話規則 = re.compile(r'\d{2}-\d{8}')
...
import re
str1 = '台北校區 地址: 25103 新北市淡水區真理街32號 電話:02-26212121'
市話規則 = re.compile(r'\d{2}-\d{8}')
result = 市話規則.search(str1)
if (result != None):
print('找到了 %s' % result.group())
else:
print('找不到市話號碼')
更多比對模式範例: 市話
但,如果想要知道比對出的電話「區碼」,例如台北02, 桃園03,可能嗎?
import re
msg = '台北校區 地址: 25103 新北市淡水區真理街32號 電話:02-26212121'
pattern = r'(\d{2})-(\d{8})' # \d{2}一組,,\d{8}一組
規則 = re.compile(pattern)
phoneNum = 規則.search(msg) # 傳回搜尋結果
print("完整號碼是: %s" % phoneNum.group()) # 顯示完整號碼
print("完整號碼是: %s" % phoneNum.group(0)) # 顯示完整號碼
print("區域號碼是: %s" % phoneNum.group(1)) # 顯示區域號碼
print("電話號碼是: %s" % phoneNum.group(2)) # 顯示電話號碼
表達式可用小括弧分組,搭配.group()取得分組內容
r'\d{2}-\d{8}'
r'(\d{2})-(\d{8})'
前2個數字第一組,'-'號後8個數字第二組
更多比對模式範例: 市話的區碼是在小括弧內?
(xx)-xxxxxxxx
'\(\d\d\)-\d\d\d\d\d\d\d\d'
以市話為例:
用逸出字元表示括弧符號
(02)-26212121
r'\(\d{2}\)-\d{8}'
import re
...
市話規則 = re.compile(r'\(\d{2}\)-\d{8}'')
...
問號?、星號*、加號+ 在正規表達式裡的意義?
import re
# 測試1
msg = 'Johnson will attend my party tonight.'
pattern = 'John((na)?son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
print(txt.group())
# 測試2
msg = 'Johnnason will attend my party tonight.'
pattern = 'John((na)?son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
print(txt.group())
import re
...
pattern = 'John((na)?son)' # 問號前的分組可有可無
規則 = re.compile(pattern)
...
問號? :出現0次或1次(可有可無)
問號?、星號*、加號+ 在正規表達式裡的意義?
# ch16_16.py
import re
# 測試1
msg = 'Please call my secretary using 02-26669999'
pattern = r'(\d\d-)?(\d{8})' # 增加?號
規則 = re.compile(pattern)
phoneNum = 規則.search(msg) # 傳回搜尋結果
print("完整號碼是: %s" % phoneNum.group()) # 顯示完整號碼
# 測試2
msg = 'Please call my secretary using 26669999'
pattern = r'(\d\d-)?(\d{8})' # 增加?號
規則 = re.compile(pattern)
phoneNum = 規則.search(msg) # 傳回搜尋結果
print("完整號碼是: %s" % phoneNum.group()) # 顯示完整號碼
問號? 的範例:省略區域號碼的電話
問號?、星號*、加號+ 在正規表達式裡的意義?
import re
# 測試1
msg = 'Johnson will attend my party tonight.'
pattern = 'John((na)*son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
print(txt.group())
# 測試2
msg = 'Johnnason will attend my party tonight.'
pattern = 'John((na)*son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
print(txt.group())
# 測試3
msg = 'Johnnanason will attend my party tonight.'
pattern = 'John((na)*son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
print(txt.group())
星號* :出現0次以上(可重複)
問號?、星號*、加號+ 在正規表達式裡的意義?
import re
# 測試1
msg = 'Johnson will attend my party tonight.'
pattern = 'John((na)+son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
print(txt.group())
# 測試2
msg = 'Johnnason will attend my party tonight.'
pattern = 'John((na)+son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
print(txt.group())
# 測試3
msg = 'Johnnanason will attend my party tonight.'
pattern = 'John((na)+son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
print(txt.group())
星號+ :出現1次以上(可重複)
re模組可以比對英文字母或標點符號嗎? 當然!
符號 | 說明 |
---|---|
\d | 0-9之間的整數字元 |
\s | 空白鍵、Tab鍵、換行字元 |
\w | 數字、字母和底線字元,相當於[A-Za-z0-9_] |
[a-z] | a-z小寫字元 |
[A-Z] | A-Z的大寫字元 |
中括弧內可以不用加上逸出字元符號
r'[0-9.]'
不須寫成r'[0-9\.]
msg = 'Johnson will attend my party.'
pattern = 'John((na)+son)'
規則 = re.compile(pattern)
txt = 規則.search(msg) # 傳回搜尋結果
msg = 'Johnson will attend my party.'
pattern = 'John((na)+son)'
txt = re.search(pattern, msg) # 傳回搜尋結果
先re.compile()後再search() 或 findall()
可改成直接用re.search(), re.findall()
msg = 'John, and Johnson will attend my party.'
pattern = '\w+' # 不限長度的單字
txt = re.findall(pattern,msg) # 傳回搜尋結果
import re
# 測試1將字串從句子分離
msg = 'John, Johnson, Johnnason and Johnnathan will attend my party.'
pattern = '\w+' # 不限長度的單字
txt = re.findall(pattern,msg) # 傳回搜尋結果
print(txt)
# 測試2將John開始的字串分離
msg = 'John, Johnson, Johnnason and Johnnathan will attend my party.'
pattern = 'John\w*' # John開頭的單字
txt = re.findall(pattern,msg) # 傳回搜尋結果
print(txt)
範例: 將英文句子單字分離,以及將前4字母是John的單字分離
import re
msg = '1 cat, 2 dogs, 3 pigs, 4 swans'
pattern = '\d+\s\w+'
txt = re.findall(pattern,msg) # 傳回搜尋結果
print(txt)
範例: 找出「數字開頭」「空白或Tab或換行字元分隔」 最後接著「數字字母底線字元」的字串
import re
# 測試1搜尋[aeiouAEIOU]字元
msg = 'John, Johnson, Johnnason and Johnnathan will attend my party.'
pattern = '[aeiouAEIOU]'
txt = re.findall(pattern,msg) # 傳回搜尋結果
print(txt)
# 測試2搜尋[2-5.]字元
msg = '1. cat, 2. dogs, 3. pigs, 4. swans'
pattern = '[2-5.]'
txt = re.findall(pattern,msg) # 傳回搜尋結果
print(txt)
範例: 搜尋aeiou不分大小寫,以及數字2至5與.的組合
Python程式設計
By Leuo-Hong Wang
Python程式設計
Lesson 13: 正規表達式 Regular Expression
- 1,154