《Python編程快速上手——讓繁瑣的工作自動化》讀書筆記6

第七章 模式匹配與正則表達式

 

好像咕咕咕太久了,又滾來更新了。這次是第七章的內容,正則表達式,如果寫的有問題,請給我留言,非常感謝。

 

在進行本章內容的筆記之前,先說一下,正則表達式是什麼。

百度給的定義如下:正則表達式是對字符串操作的一種邏輯共識,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符串”,這個“規則字符串”用來表達對字符串的一種過濾邏輯。(感覺其實說的很清楚了,再簡單一點就是說:類似一種速記的邏輯,用自己特定的方法表示信息)

 

不用正則表達式來查找文本模式

首先,書上舉的例子,是在一些字符串中查找電話號碼。電話號碼的格式是xxx-xxx-xxxx。我先假定看到這篇讀書筆記的讀者們,都已經瞭解了Python,或者有其他語言的基礎,那麼,先請大家思考一下,應該怎麼來實現呢?

 

最簡單,完全不管包裝的方法就是直接從鍵盤或者文件輸入字符串,然後在“主函數”部分用if來進行判斷。然後關於字符串、元組、列表部分如果到這裏仍有疑問,就麻煩翻一下前面的內容,在此不贅述啦。

以下是書中提供的代碼(我不記得我有沒有上傳過代碼包了,如果沒有我回頭上傳一下)

def isPhoneNumber(text):
    if len(text) != 12:
        return False  # not phone number-sized
    for i in range(0, 3):
        if not text[i].isdecimal():
            return False  # not an area code
    if text[3] != '-':
        return False  # does not have first hyphen
    for i in range(4, 7):
        if not text[i].isdecimal():
            return False  # does not have first 3 digits
    if text[7] != '-':
        return False  # does not have second hyphen
    for i in range(8, 12):
        if not text[i].isdecimal():
            return False  # does not have last 4 digits
    return True  # "text" is a phone number!

print('415-555-4242 is a phone number:')
print(isPhoneNumber('415-555-4242'))
print('Moshi moshi is a phone number:')
print(isPhoneNumber('Moshi moshi'))

(輸出展示)

415-555-4242 is a phone number:

True

Moshi moshi is a phone number:

False

幾點註釋:

1.  isdecimal() 方法檢查字符串是否只包含十進制字符。這種方法只存在於unicode對象。

注意:定義一個十進制字符串,只需要在字符串前添加 'u' 前綴即可。

isdecimal()方法語法:

str.isdecimal()

如果字符串是否只包含十進制字符返回True,否則返回False

2.調用函數的方法和其他語言差距不大

3.一定要注意空格,我太長時間沒寫了,導致長時間報錯(我真應該找到我的遊標卡尺,枯了)

"

isPhoneNumber()函數的代碼進行幾項檢查,看看text中的字符串是不是有效的電話號碼。如果其中任意一項檢查失敗,函數就返回False。代碼首先檢查該字符串是否剛好有12個字符➊。然後它檢查區號(就是text中的前3個字符)是否只包含數字❷。函數剩下的部分檢查該字符串是否符合電話號碼的模式:號碼必須在區號後出現第一個短橫線❸, 3個數字❹,然後是另一個短橫線❺,最後是4個數字❻如果程序執行通過了所有的檢查,它就返回True❼。

"

然後,再利用前面提到的切片的方法,我們還可以從一串字符(不像前面的直接判斷一小段一小段的字符串是不是電話號碼)中提取電話號碼。代碼如下:

def isPhoneNumber(text):
    if len(text) != 12:
        return False  # not phone number-sized
    for i in range(0, 3):
        if not text[i].isdecimal():
            return False  # not an area code
    if text[3] != '-':
        return False  # does not have first hyphen
    for i in range(4, 7):
        if not text[i].isdecimal():
            return False  # does not have first 3 digits
    if text[7] != '-':
        return False  # does not have second hyphen
    for i in range(8, 12):
        if not text[i].isdecimal():
            return False  # does not have last 4 digits
    return True  # "text" is a phone number!

'''print('415-555-4242 is a phone number:')
print(isPhoneNumber('415-555-4242'))
print('Moshi moshi is a phone number:')
print(isPhoneNumber('Moshi moshi'))'''
message='Call me at 415-555-1011 tomorrow. 415-555-9999 is my office'

for i in range(len(message)):
    chunk = message[i:i+12]
    if isPhoneNumber(chunk):
        print('Phone number found: '+ chunk)
print('Done')

(輸出展示)

Phone number found: 415-555-1011
Phone number found: 415-555-9999
Done

在for 循環的每次迭代中, 取自message 的一段新的 12個字符被賦給變量chunk❶.例如,在第一次迭代, i是0, chunk被賦值爲message[0:12] (即字符串'Call me at 4').在下次選代,i是1, chunk 被賦值爲message[1:13] (字符串'all me at 4I')。
將chunk傳遞給isPhoneNumber(),看看它是否符合電話號碼的模式❷。如果符合,就打印出這段文本。
繼續遍歷message,最終chunk中的12個字符會是一個電話號碼。該循環遍歷了整個字符串,測試了每一段12個字符,打印出所有滿足isPhoneNumber()的chunk。當我們遍歷完message,就打印出Done.
在這個例子中,雖然message中的字符串很短,但它也可能包含上百萬個字符,程序運行仍然不需要一秒鐘。 使用正則表達式查找電話號碼的類似程序,運行也不會超過一秒鐘, 但用正則表達式編寫這類程序會快得多”

 

用正則表達式查找文本模式

我們還是回到上面的問題,電話號碼,因爲書呢是美國人寫的,就按照他們的習慣,電話號碼格式是xxx-xxx-xxxx,那麼正則表達式會長什麼樣子呢?就是用約定俗成的符號\d來代替我前面隨意用的x,\d\d\d-\d\d\d-\d\d\d\d,因爲人呢是特別懶惰的,當然也是爲了儘量避免失誤,所以還有一個簡化版本的:\d\d\d-\d\d\d-\d\d\d\d=》\d{3}-\d{3}-\d{4},通過花括號中間加數字表示前面的符號重複幾遍。

創建正則表達式對象

Python中所有的正則表達式都在re模塊中

import re

如果不導入就會報錯:NameError:balabalabala……

如果我們要創建一個Regex對象來匹配電話號碼模式(讓phoneNumRegex中包含一個Regex對象):

phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')

匹配Regex對象

通過search()方法查找字符串

那麼前面的def部分+切片查找部分就被search()替代了

import re

phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search('My number is 415-555-4242.')
print('phone number found: '+ mo.group())

(輸出展示)

phone number found: 415-555-4242

幾點註釋:

1.search():http://www.cnblogs.com/aaronthon/p/9435967.html

2.group():https://www.cnblogs.com/erichuo/p/7909180.html

 

用正則表達式匹配更多模式

可以使用括號分組(搭配group()使用)

比如上面提到的:\d\d\d-\d\d\d-\d\d\d\d=》(\d\d\d)-(\d\d\d-\d\d\d\d)

上面的代碼改成:

import re

phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phoneNumRegex.search('My number is 415-555-4242.')
print(mo.group(1))
'''
print(mo.group(2))
print(mo.group(0))
print(mo.group())
print(mo.group(1)+mo.group(2))
'''

(輸出展示)

415

如果把註釋去掉,輸出如下:

415
555-4242
415-555-4242
415-555-4242
415555-4242

import re

phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phoneNumRegex.search('My number is 415-555-4242.')
'''
print(mo.group(1))
print(mo.group(2))
print(mo.group(0))
print(mo.group())
print(mo.group(1)+mo.group(2))
'''

areaCode,mainNumber= mo.groups()
print(areaCode)
print(mainNumber)

(輸出展示)

415
555-4242

括號在正則表達式中有特殊的含義,但是如果你需要在文本中匹配括號,怎麼辦?例如,你要匹配的電話號碼,可能將區號放在一對括號中。 在這種情況下,就需要用倒斜槓對(和)進行字符轉義。

import re

phoneNumRegex = re.compile(r'(\(\d\d\d\)) (\d\d\d-\d\d\d\d)')
mo = phoneNumRegex.search('My number is (415) 555-4242.')
print(mo.group(1))
print(mo.group(2))
print(mo.group(1)+' '+mo.group(2))

(輸出展示)

(415)
555-4242
(415) 555-4242

 

用管道匹配多個分組

---------------------------------未完,找時間填坑-------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

參考:

http://www.runoob.com/python/att-string-isdecimal.html

http://www.cnblogs.com/aaronthon/p/9435967.html

https://www.cnblogs.com/erichuo/p/7909180.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章