導航:
1、正規表示式元字元
2、預定義字符集
3、re模組常用函式
4、注意事項
正規表示式在很多語言裡都支援,python也不例外,re模組就是正規表示式的應用
正規表示式對字串的邏輯操作,主要是對字串的一種過濾,用“元字元” 與“普通字元”組成一個字串規則對已知的字串或文字過濾出自己想要的字串
1、正規表示式元字元
轉義字元,將後邊緊跟著的字元變成特殊字元,或將後邊的特殊字元變成普通字元 如:在正規表示式中,” |
|
^ | 匹配第一行行首,匹配多行需要傳參 flags=re.MULTILINE |
$ | 匹配最後一行行尾,匹配多行需要傳參 flags=re.MULTILINE |
. | 除” “” “外,匹配任意的單個字元,要使”.”匹配換行符,flags=re.DOTALL |
| | 或,如 “aaa|bbb|ccc”,表示”aaa”,”bbb”,”ccc”三選一 |
? | 匹配前邊的子表示式0次或1次,等價於{0,1} |
+ | 匹配前邊的子表示式1次或多次,等價於{1,} |
* | 匹配前邊的子表示式0次或多次,,等價於{0,} |
{} |
{n}匹配前邊的子表示式n次,{n,}匹配前邊的子表示式至少n次 即:>= n, {n,m}匹配前邊的子表示式n~m次,即:n<= 表示式 <=m |
() | 分組,從1開始,從左至右數”(“為第幾組,下標0為全部分組 |
[] |
字符集匹配[]中的人一個字元,之匹配一次,如[abc]:表示”a”,”b”,”c”三選一。 也可以給定範圍(必須是連續的才行),如[a-z]:表示a到z任意一個字元。 還可以取反,如[^abc]:除”a”,”b”,”c”外的任意字元。 注:[]中只有”^”,”-“,””三個特殊字元,其中””代表轉義字元, 其它的都代表原本普通的字元,如:[.]只是一個普通的點字元 |
注:要使用元字元本身的普通字元,請使用轉義字元轉義一下,如 :”(” 在正規表示式中代表普通給”(“字元,其它的雷同
分組的用法:
( um) |
引用指定第幾分組的值 |
(?P<name>) | 指定分組別名”name” |
(?P=name) | 引用指定別名的分組的值 |
(?:) |
相當於去分組化,變成”與”()子集, 如:”abc(?:qqq|www)”–>相當於”abcqqq|abcwww” |
(具體用法請看下邊(search函式))
2、預定義字符集
匹配一個單詞邊界,也就是指單詞和空格間的位置, 其它特殊字元也可以是單詞的邊界,如”#”,”$”,”&”,”*”等 |
|
B | 匹配非單詞邊界 |
d | 匹配一個數字字元。等價於[0-9] |
D | 匹配一個非數字字元。等價於[^0-9 |
s |
匹配任何不可見字元,包括空格、製表符、換頁符等, 等價於[ f v] |
S | 匹配任何可見字元。等價於[^ f
v] |
w |
匹配包括下劃線的任何單詞字元。這裡的”單詞”字元使用Unicode字符集, 類似但不等價於“[A-Za-z0-9_]”,還包含漢字等它國字元 |
W |
匹配任何非單詞字元。這裡的”單詞”字元使用Unicode字符集, 類似但不等價於“[^A-Za-z0-9_]”,還包含漢字等它國字元 |
3、re模組常用函式
在這裡我要先說明一下 flags 的用法
re.A 或 re.ASCII | 使用ASCII字符集進行匹配(不常用) |
re.I 或 re.IGNORECASE | 忽略大小寫匹配 |
re.L 或 re.LOCALE |
使用當前預定字元類 w W B s S 取決於當前區域設定(不常用) |
re.U 或 re.UNICODE |
使用Unicode字元類 w W B s S d D 取決於unicode定義的字元屬性(不常用) |
re.M 或 re.MULTILINE | 多行匹配,使”^”,”$”可以在每一行中都進行匹配 |
re.S 或 re.DOTALL | 使 “.” 可以匹配換行符” “,” “ |
re.X 或 re.VERBOSE | 去掉正規表示式中的所有空格符(不常用) |
1)re.findall(pattern, string, flags=0)
按照規則匹配整個字串,返回匹配結果的列表
1 >>> re.findall(r"hello", "hello world hello") # 普通匹配 2 [`hello`, `hello`] 3 >>> re.findall(r"^hello", "hello world hello") # 匹配開頭 4 [`hello`] 5 >>> re.findall(r"^hello", "hello world hello", flags=re.MULTILINE) # 多行匹配開頭 6 [`hello`, `hello`] 7 >>> re.findall(r"hello$", "hello world hello") # 匹配結尾 8 [`hello`] 9 >>> re.findall(r"d+", "aaa111bbb222ccc333") # 匹配數字 10 [`111`, `222`, `333`] 11 >>> re.findall(r"d{2}", "aaa111bbb222ccc333") # 匹配兩位的數字 12 [`11`, `22`, `33`] 13 >>> re.findall(r"ab|cd", "ab000cd00") # 匹配"ab"或"cd" 14 [`ab`, `cd`] 15 >>> re.findall(r"(", "ab(cd")) # 匹配"(" 16 [`(`] 17 18 >>> re.findall(r"(abc)+", "abcabcabc") # 想要匹配多個"abc",使用分組時會優先把分組的內容返回 19 [`abc`] 20 >>> re.findall(r"(?:abc)+", "abcabcabc") # 想要匹配多個"abc",(?:)把分組去掉,變成一個普通的字串 21 [`abcabcabc`]
2)re.finditer(pattern, string, flags=0)
finditer與findall相似,只不過finditer返回一個迭代器,迭代器中每一個元素都是re.Match物件,通過group()可以獲取值
1 r = re.finditer("hello", "hello world hello") 2 for i in r: 3 print(i.group()) 4 5 # 輸出結果 6 hello 7 hello
3)re.search(pattern, string, flags=0)
search函式只返回第一個匹配到的結果,成功返回re.Match物件,否則返回None。
1 >>> re.search(r"hello", "hello world hello") 2 <_sre.SRE_Match object; span=(0, 5), match=`hello`> # 可以看到只返回了第一個"hello" 3 >>> re.search(r"hello", "hello world hello").group() 4 `hello` 5 6 >>> re.search(r"(abc) 1", "abc abc").group() # 1 引用分組1的值 7 `abc abc` 8 >>> re.search(r"(?P<name>abc) (?P=name)", "abc abc").group() # (?P=name) 引用分組別名"name"的值 9 `abc abc` 10 11 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group() 12 `zhansan 23` 13 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group(0) # 分組0--即匹配的結果 14 `zhansan 23` 15 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group(1) # 分組1的值 16 `zhansan` 17 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group(2) # 分組2的值 18 `23` 19 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group("name") # 分組別名name的值 20 `zhansan` 21 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group("age") # 分組別名age的值 22 `23`
4)re.match(pattern, string, flags=0)
match從開始處進行匹配,成功返回re.Match物件,否則返回None。類似於於findall程式碼中的第3行
1 >>> re.findall(r"^abc", "abcooooo") 2 [`abc`] 3 >>> re.match(r"abc", "abcooooo").group() 4 `abc`
5)re.sub(pattern, repl, string, count=0, flags=0)
sub按照給定的規則將string字串中的相應的片段替換為repl,count 最多替換的次數,count=0預設為全部替換,返回替換後的字串
1 >>> re.sub(r"d+", "$", "aaa1bb2ccc333") # 將連續的數字變成"$" 2 `aaa$bb$ccc$`
6)re.subn(pattern, repl, string, count=0, flags=0)
與sub相識,count 最多替換的次數,count=0預設為全部替換,返回 一個元組,下標0為替換後的字串,下標1成功替換的次數
1 >>> re.subn(r"d+", "$", "aaabbccc") 2 (`aaabbccc`, 0) 3 >>> re.subn(r"d+", "$", "aaa11bb22ccc") 4 (`aaa$bb$ccc`, 2) 5 >>> re.subn(r"d+", "$", "aaa11bb22ccc", 1) # 最多替換1次 6 (`aaa$bb22ccc`, 1) 7 >>> re.subn(r"d+", "$", "aaa11bb22ccc", 10) # 最多替換10次 8 (`aaa$bb$ccc`, 2) # 成功替換2次
7)re.split(pattern, string, maxsplit=0, flags=0)
通過給定規則,將string進行切割,maxsplit最多切割次數,maxsplit=0預設全部切割,返回切割結果的字串列表
1 >>> re.split(r"@", "a#b#c#d#e") # 沒有找到"@",不切割 2 [`a#b#c#d#e`] 3 >>> re.split(r"#", "a#b#c#d#e") # 按"#"對字串進行切割 4 [`a`, `b`, `c`, `d`, `e`] 5 >>> re.split(r"#", "a#b#c#d#e", 2) # 按"#"對字串進行切割,最多切割2次 6 [`a`, `b`, `c#d#e`]
8)re.compile(pattern, flags=0)
返回一個正規表示式的物件
1 >>> rg = re.compile(r"d+", flags=0) 2 >>> re.findall(rg, "a1bb22ccc333") 3 [`1`, `22`, `333`]
4、注意事項
1)”r” 原生字串的使用,在字串前加 “r” 或 “R” 表示這個字串為原生字串,即所有的字元都表示普通字元,無特殊字元,常在正則、路徑中應用
1 >>> print(r"aa bb") 2 aa bb 3 >>> print(len(r"aa bb")) 4 6 5 >>> print("aa bb") 6 aa 7 bb 8 >>> print(len("aa bb")) 9 5
可以看到第四行,字串長度為”6″ ,即 “” “n” 是兩個字元。
第6、7行輸出了兩行,第9行字串長度”5″,說明 ”
” 是一個換行符
2)例子:如果需要匹配 “” 該如何寫正規表示式(重點)
1 >>> re.findall(r"aa\", r"aab") 2 [`aa\`] 3 >>> re.findall("aa\", r"aab") 4 Traceback (most recent call last): 5 # 報錯內容····太多,就這樣顯示就好 6 >>> re.findall("aa\\", r"aab") 7 [`aa\`] 8 >>> print(len(re.findall(r"aa\", r"aab")[0])) 9 3
在這裡首先要說明一下,在python中,輸出帶引號的字串中有 “” 字元,是轉義後看到的字元,即 “\”
可以看到,在匹配帶轉義字元的正規表示式的中帶 “r” 和不帶 “r” 的寫法有很大的區別
其中的原因是python直譯器在解釋字串的時候會按自己的規則將字串翻譯了一便。
如第3行,”aa\” 經過python 直譯器翻譯之後,已經變成了 r”aa” 這樣的原生字串,傳遞給re模組的時候,re模組無法解析單個 “” 轉義字元,所以會報錯。
如果要匹配 “” 的普通字元,正規表示式需要寫出 “\” ,所以第6行傳遞的時候需要 4 個”\\” ,經過python解釋之後,變成 r”\” 就正確了。
綜上所述,在寫正規表示式的時候還是在前邊加個 “r” 這樣或許會避免很多的問題(個人建議,特別是在網上找的正規表示式)