星期四, 11月 19, 2020

Python re 筆記 1-1: Regular Expression HOWTO/Simple Patterns

Regular Expression HOWTO  是 Python 官網推薦的 "正規表示法" 學習文件,在此翻譯和筆記心得,順其章節但不逐字翻。

Introduction 介紹正規表示式

正規表示式 Regular expression (REs, reges, reges patterns) 被用以在 string 中找 pattern。

(更務實的理解是用匹配詞 (pattern) 在文 (string) 中找出特定字。做為 python 使用者,在 import re 後,對 re 提供的各函式提供 pattern,也就是符合正規表示式文法的 regular expression。對 re 來說,pattern 字串編譯成 pattern object 後才有搜尋作用)


Simple Patterns 簡易匹配詞 

Matching Characters 

最直觀的匹配詞 pattern 就是想找的特定字。比如想找 test,匹配詞就是 test。
但有許多具有功能性的 metacharacters (匹配元),它們出現在 pattern 中具有其他意義。以下綠底為匹配元:
. ^ $ * + ? { } [ ] \ | ( )

方框 []:提供任一可匹配的[characters] ,和任何不可匹配的 [^characters] 
  • 方框內的任一字元都可找出
    • 比如 [abc] ,表示可找出 a 或 b 或 c 。
    • 連續性的字元集,比如 [abc] ,可用 '-' 表示連續性,表示為 [a-c] 。小寫英文字母常以 [a-z]  表示。
    • 匹配元在方框內也可以當成普通字元用。比如  [akm$] ,錢字號$是匹配元,作用為置後,但在方框內只是個普通可比對的字元。所以[akm$]可找出 'a''k', 'm',和 '$'
    • (私下覺得方框還原了匹配詞就是比對字的原始定義)
  • 在方框內首字元用 '^' 表示,則任何在方框內的字元都不可匹配,也就是 "所有不在方框內的字都符合" !!
    • 比如 [^5] ,5 以外的字元都可找出。
    • 注意當 '^' 不在方框首位,就當作普通字。比如[5^] 可找出 '5' 和 '^'
反斜線 是最重要的匹配元,有跳脫功能性帶入功能性的作用。

跳脫功能性之反斜線 \
  • Pattern內存在的匹配元有功能,無法視為比對內容。比如 [ 或 \ ,不可視為 "找左方框" 和 "找反斜線"。
  • 不過,將匹配元前配上反斜線\後,匹配元跳脫功能性回歸成一般字元,比方 \[ 和 \\ ,就視為 "找左方框"  和 "找反斜線"。
帶入功能性之反斜線 \:普通字元要怎麼有功能性呢?用久了,我們會期待數字可用某個字元表示,所有字母也用某字元表示,那這些普通字變成功能字,也是由反斜線帶入
  • \d:等義 [0-9],所有數字。
  • \D:等義 [^0-9],所有非數字。
  • \s:等義 [\t\n\r\f\v],所有空白字元。\t是水平跳格,\v是垂直跳格;\r是回車,\n是新行;\f換頁。
  • \S:等義 [^\t\n\r\f\v],所有非空白字元。
  • \w:等義 [a-zA-Z0-9_],所有字母數字元。
  • \W:等義 [^a-zA-Z0-9_],所有非字母數字元。
最懶點字元 .:可匹配任何非新行\n的字元。re 還提供 re.DOTALL 可匹配一切含新行\n的任何字元。

剩下的匹配元 * + ? { } | ( ) 將在後文說明

重複量詞

描述某字元某詞的重複次數。

米字號 *:0或多次

加字號 +:一次以上

問字號 ?:無或有(只出現一次)
  • 比如 home-?brew 可找出 'homebrew' 或 'home-brew'
大括號 {m,n}:指定重複次數
  • 出現 m~n 次:至少 m 次,最多 n 次。
    • 省略 m 次表示至少 0 次。
    • 省略 n 表示至多任意數量,所以有 {0,}{1,}{0,1} 等義 *,+ ,? 的用法
重複字元 * 有貪婪性,RE 會盡可能找出最多,之後的比對不合後,才減少重複量,返回前字元再比對。以 pattern  a[bcd]*b 找 string  'abcbd' 為例。


Matched

Explanation

1

a

狀態: string  'abcbd'; pattern  a[bcd]*b,工作pattern是 a. 

工作RE找到 a. 

2

abcbd

狀態: string剩  'bcbd'; pattern剩 [bcd]*b, 工作patter是[bcd]*

工作: RE 以 [bcd]* 貪婪比對,一路找到底。狀態:string 剩  '' ,pattern 剩 b

3

Failure

狀態: string剩 ''; pattern 剩 b , 工作patter是 b.

工作RE 找尾字 b,但 string 已空無字元可找,比對失敗

4

abcb

工作返回,讓工作pattern 回到[bcd]*,並將之前[bcd]* 找出字減一字元,也就是 [bcd]* 只找出 bcb,整體只找出 'abcb'

5

Failure

狀態: string剩'd'; pattern剩 b,工作patter是b

工作RE再找尾字 b,但 string 剩 'd' 找不出 b ,失敗。

6

abc

工作返回將之前[bcd]* 找出字減一字元,也就是 [bcd]* 只找出 bc,整體只找出 'abc'

6

abcb

狀態: string剩'bd'; pattern剩b,工作patter是 b. 

工作:再試b。這回找出'b'整體找到符合pattern 的 'abcb'


到 RE末端(pattern 結束)匹配出 'abcb' 。這說明了匹配引擎,會先在貪婪性匹配(比如 [bcd]*)上盡可能地把整個 string 找完,若剩下的不匹配,會返回貪婪性匹配成果的尾字元,再試剩下的匹配。如果不成功會一直試到[bcd]*找到的成果到歸零。而歸零就算失敗找不到。
 
(這段詳述了貪婪性匹配的作法和修正。Simple Patterns 後段就請看原文或機翻)



來源與參考: 
1. https://docs.python.org/3/howto/regex.html#regex-howto,Python 官網推薦文。