原網址:https://blog.csdn.net/lisonglisonglisong/article/details/39697137
正則表達式(Regular Expression)是字符串處理的常用工具,通常被用來檢索、替換那些符合某個模式(Pattern)的文本。很多程序設計語言都支持正則表達式,像Perl、Java、C/C++。在 Python 中是通過標准庫中的re 模塊 提供對正則的支持。
一、正則表達式介紹
在使用 re 模塊之前,先來了解一下正則表達式的基本語法。
1)用途
通過使用正則表達式,可以:
-
測試字符串內的模式。—— 例如,可以測試輸入字符串,以查看字符串內是否出現電話號碼模式或信用卡號碼模式。這稱為數據驗證。
-
替換文本。—— 可以使用正則表達式來識別文檔中的特定文本,完全刪除該文本或者用其他文本替換它。
-
基於模式匹配從字符串中提取子字符串。—— 可以查找文檔內或輸入域內特定的文本。
2)語法
本文主要介紹正則的基本語法以及 re 模塊的使用,不包括如何編寫高效的正則表達式、如何優化正則表達式,這些主題請看其他教程。
下圖列出了Python支持的一些正則表達式元字符和語法:
3)貪婪模式與非貪婪模式
“貪婪模式”總是嘗試匹配盡可能多的字符;“非貪婪模式”則相反,總是匹配盡可能少的字符。例如,用"ab*"如果用於查找"abbbc",將找到"abbb"。而如果使用非貪婪的數量詞"ab*?",將找到"a"。
二、使用 re 模塊
下面我們開始來使用 re 模塊。
1)編譯正則表達式
re 模塊提供了 re.compile() 函數將一個字符串編譯成 pattern object,用於匹配或搜索。函數原型如下:
re.compile(pattern, flags=0)
re.compile() 還接受一個可選的參數 flag,用於指定正則匹配的模式。關於匹配模式,后面將會講到。
p = re.compile('ab*', re.IGNORECASE)
2)反斜杠的困擾
在 python 的字符串中,\ 是被當做轉義字符的。在正則表達式中,\ 也是被當做轉義字符。這就導致了一個問題:如果你要匹配 \ 字符串,那么傳遞給 re.compile() 的字符串必須是"\\\\"。
由於字符串的轉義,所以實際傳遞給 re.compile() 的是"\\",然后再通過正則表達式的轉義,"\\" 會匹配到字符"\"。這樣雖然可以正確匹配到字符 \,但是很麻煩,而且容易漏寫反斜杠而導致 Bug。那么有什么好的解決方案呢?
原始字符串很好的解決了這個問題,通過在字符串前面添加一個r,表示原始字符串,不讓字符串的反斜杠發生轉義。那么就可以使用r"\\"
來匹配字符\
了。
3)pattern object 執行匹配
一旦你編譯得到了一個 pattern object,你就可以使用 pattern object 的方法或屬性進行匹配了,下面列舉幾個常用的方法,更多請看這里。
regex.match(string[, pos[, endpos]])
:
- 匹配從 pos 到 endpos 的字符子串的開頭。匹配成功返回一個 match object,不匹配返回 None。
- pos 的默認值是0,endpos 的默認值是 len(string),所以默認情況下是匹配整個字符串的開頭。
import re pattern = re.compile("ar{1}") print(pattern.match("army")) # "ar"在開頭,匹配成功 print(pattern.match("mary")) # "ar"不在開頭,匹配失敗 print(pattern.match("mary", 1)) # "ar"不在開頭,但在子串的開頭 # 輸出結果: # <_sre.SRE_Match object; span=(0, 2), match='ar'> # None # <_sre.SRE_Match object; span=(1, 3), match='ar'>
regex.search(string[, pos[, endpos]])
:
- 掃描整個字符串,並返回它找到的第一個匹配(Match object)。
- 和 regex.match() 一樣,可以通過 pos 和 endpos 指定范圍。
pattern = re.compile("ar{1}") match = pattern.search("mary") # search print(match) # 輸出結果: # <_sre.SRE_Match object; span=(1, 3), match='ar'>
regex.findall(string[, pos[, endpos]])
:
- 找到所有匹配的子串,並返回一個 list 。
- 可選參數 pos 和 endpos 和上面一樣。
pattern = re.compile(r"\d+") lst = pattern.findall("abc1def2rst3xyz") # findall print(lst) # 輸出結果: # ['1', '2', '3']
regex.finditer(string[, pos[, endpos]])
:
- 找到所有匹配的子串,並返回由這些匹配結果(match object)組成的迭代器。
- 可選參數 pos 和 endpos 和上面一樣。
pattern = re.compile(r"\d+") p = pattern.finditer("abc1def2rst3xyz") for i in p: print(i) # 輸出結果: # <_sre.SRE_Match object; span=(3, 4), match='1'> # <_sre.SRE_Match object; span=(7, 8), match='2'> # <_sre.SRE_Match object; span=(11, 12), match='3'>
4)match object 獲取結果
在上面講到,通過 pattern object 的方法(除 findall 外)進行匹配得到的返回結果都是 match object。每一個 match object 都包含了匹配到的相關信息,比如,起始位置、匹配到的子串。那么,我們如何從 match object 中提取這些信息呢?
match object 提供了一些方法,下面列舉幾個常用的方法,更多請看這里。
- 返回 match object 中的字符串。
- 每一個 ( ) 都是一個分組,分組編號從1開始,從左往右,每遇到一個左括號,分組編號+1。
- 組 0 總是存在的,它就是整個表達式 。
- 沒有參數時,group1默認為0,這時返回整個匹配到的字符串。
- 指定一個參數(整數)時,返回該分組匹配到的字符串。
- 指定多個參數時,返回由那幾個分組匹配到的字符串組成的 tuple。
pattern = re.compile(r"(\w+) (\w+)") m = pattern.match("Kobe Bryant, Lakers") print(m) # <_sre.SRE_Match object; span=(0, 11), match='Kobe Bryant'> print(m.group()) # Kobe Bryant print(m.group(1)) # Kobe print(m.group(2)) # Bryant print(m.group(1, 2)) # ('Kobe', 'Bryant')
- 返回由所有分組匹配到的字符串組成的 tuple。
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632") >>> m.groups() ('24', '1632')
- 沒有參數時,返回匹配到的字符串的起始位置。
- 指定參數(整數)時,返回該分組匹配到的字符串的起始位置。
pattern = re.compile(r"(\w+) (\w+)") m = pattern.match("Kobe Bryant, Lakers") print(m.start()) # 0 print(m.start(2)) # 5
- 沒有參數時,返回匹配到的字符串的結束位置。
- 指定參數(整數)時,返回該分組匹配到的字符串的結束位置。
pattern = re.compile(r"(\w+) (\w+)") m = pattern.match("Kobe Bryant, Lakers") print(m.end()) # 11 print(m.end(1)) # 4
- 返回一個二元 tuple 表示匹配到的字符串的范圍,即 (start, end)。
- 指定參數時,返回該分組匹配到的字符串的 (start, end)。
pattern = re.compile(r"(\w+) (\w+)") m = pattern.match("Kobe Bryant, Lakers") print(m.span()) # (0, 11) print(m.span(2)) # (5, 11)
5)模塊級別的函數
上面講到的函數都是對象的方法,要使用它們必須先得到相應的對象。本節將介紹一些Module-Level Functions,比如 match(),search(),findall() 等等。你不需要創建一個 pattern object 就可以直接調用這些函數。
re.compile(pattern, flags=0)
:上面已經介紹過。
re.match(pattern, string, flags=0)
:
pattern = re.compile(r"(\w+) (\w+)") m = pattern.match("Kobe Bryant, Lakers") # 相當於 m = re.match(r"(\w+) (\w+)","Kobe Bryant, Lakers")
re.search(pattern, string, flags=0)
:
pattern = re.compile(r"(\w+) (\w+)") m = pattern.search("Kobe Bryant, Lakers") # 相當於 m = re.search(r"(\w+) (\w+)","Kobe Bryant, Lakers")
re.findall(pattern, string, flags=0)
:與上面類似。
re.finditer(pattern, string, flags=0)
:與上面類似。
6)編譯標志(匹配模式)
在講 re.compile() 函數時,曾說到該函數還接受可選的第二個參數,用以設置匹配模式。可選的匹配模式有:
-
re.IGNORECASE:忽略大小寫,同 re.I。
-
re.MULTILINE:多行模式,改變^和$的行為,同 re.M。
-
re.DOTALL:點任意匹配模式,讓'.'可以匹配包括'\n'在內的任意字符,同 re.S。
-
re.LOCALE:使預定字符類 \w \W \b \B \s \S 取決於當前區域設定, 同 re.L。
-
re.ASCII:使 \w \W \b \B \s \S 只匹配 ASCII 字符,而不是 Unicode 字符,同 re.A。
-
re.VERBOSE:詳細模式。這個模式下正則表達式可以是多行,忽略空白字符,並可以加入注釋。主要是為了讓正則表達式更易讀,同re.X。例如,以下兩個正則表達式是等價的:
a = re.compile(r"""\d + # the integral part \. # the decimal point \d * # some fractional digits""", re.X) b = re.compile(r"\d+\.\d*")
三、修改字符串
第二部分講的是字符串的匹配和搜索,但是並沒有改變字符串。下面就講一下可以改變字符串的操作。
1)分割字符串
split()
函數在匹配的地方將字符串分割,並返回一個 list。同樣的,re 模塊提供了兩種 split 函數,一個是 pattern object 的方法,一個是模塊級的函數。
regex.split(string, maxsplit=0)
:
- maxsplit用於指定最大分割次數,不指定將全部分割。
pattern = re.compile(r"[A-Z]+") m = pattern.split("abcDefgHijkLmnoPqrs") print(m) # 輸出結果: # ['abc', 'efg', 'ijk', 'mno', 'qrs']
re.split(pattern, string, maxsplit=0, flags=0)
:
- 模塊級函數,功能與 regex.split() 相同。
- flags用於指定匹配模式。
m = re.split(r"[A-Z]+","abcDefgHijkLmnoPqrs") print(m) # 輸出結果: # ['abc', 'efg', 'ijk', 'mno', 'qrs']
2)搜索與替換
另一個常用的功能是找到所有的匹配,並把它們用不同的字符串替換。re 模塊提供了sub()
和subn()
來實現替換的功能,而它們也分別有自己兩個不同版本的函數。
regex.sub(repl, string, count=0)
:
- 使用 repl 替換 string 中每一個匹配的子串,返回替換后的字符串。若找不到匹配,則返回原字符串。
- repl 可以是一個字符串,也可以是一個函數。
- 當repl是一個字符串時,任何在其中的反斜杠都會被處理。
- 當repl是一個函數時,這個函數應當只接受一個參數(Match對象),並返回一個字符串用於替換。
- count 用於指定最多替換次數,不指定時全部替換。
def fun(m): return m.group().upper() pattern = re.compile(r"like", re.I) s1 = pattern.sub(r"love", "I like you, do you like me?") s2 = pattern.sub(fun, "I like you, do you like me?") print(s1) print(s2) # 輸出結果: # I love you, do you love me? # I LIKE you, do you LIKE me?
re.sub(pattern, repl, string, count=0, flags=0)
:
- 模塊級函數,與 regex.sub() 函數功能相同。
- flags 用於指定匹配模式。
regex.subn(repl, string, count=0)
:
- 同 sub(),只不過返回值是一個二元 tuple,即
(sub函數返回值, 替換次數)
。
re.subn(pattern, repl, string, count=0, flags=0)
:
- 模塊級函數,功能同 regex.subn()。