一、概述
正規表示式(regular expression)又稱 規則表示式,是一種文字模式(pattern)。正規表示式使用一個字串來描述、匹配具有相同規格的字串,通常被用來檢索、替換那些符合某個模式(規則)的文字。正規表示式的核心功能就是處理文字。正規表示式並不僅限於某一種語言,但是在每種語言中有細微的差別。
二、re模組
在 Python 中提供了 re 模組來使用正規表示式。每一個字串都可以視為一個簡單的正規表示式。
re.findall(pattern, string, flags=0) # 去整個文字中查詢所有符合正規表示式的文字
re.search(pattern, string, flags=0) # 去整個文字中去匹配,返回匹配成功的第一個
re.match(pattern, string, flags=0) # 從開始位置開始匹配,返回匹配成功的第一個
re.split(pattern, string, maxsplit=0, flags=0) # 根據正規表示式切割字串
re.Match.group([group1, ...]) # 返回這個匹配物件或者特定子組
re.Match.groups(default=None) # 返回一個唯一或者全部子組的元組
在 Python 中,主要有兩種方法完成模式匹配:“搜尋”(searching),即在字串任意部分中搜尋匹配的模式;而 “匹配”(matching)是指判斷一個字串能否從起始處全部或者部分匹配某個模式。搜尋透過 search() 函式或方法來實現,而匹配是呼叫 match() 函式或方法實現。
match() 函式試圖從字串的起始部分對模式進行匹配。如果匹配成功,就返回一個匹配物件(Match 物件);如果匹配失敗,就返回 None,匹配物件(Match 物件)的 group() 方法能夠用於顯示那個成功的匹配。
search() 的工作方式與 match() 完全一致,不同之處在於 search() 會用它的字串引數,在任意位置對給定正規表示式模式搜尋第一次出現的匹配情況。如果搜尋到成功的匹配,就會返回一個匹配物件(Match 物件);否則,返回 None。
由此可見,match() 試圖從字串的起始部分開始匹配模式,而 search() 函式不但會搜尋模式在字串中第一次出現的位置,而且嚴格地對字串從左到右搜尋。
findall() 查詢字串中某個正規表示式模式全部的非重複出現情況。這與 search() 在執行字串搜尋時類似,但與 match() 和 search() 的不同之處在於,findall() 總是返回一個列表。如果 findall() 沒有找到匹配的部分,就返回一個空列表,但如果匹配成功,列表將包含所有成功的匹配部分(從左到有按出現順序排列)。
import re
content = "你好啊,小櫻同學!歡迎你加入小櫻班。從現在開始你就是我的朋友啊。小櫻同志,請多多關照。"
regex = "小櫻"
result = re.findall(regex,content)
print(result)
result = re.search(regex,content)
print(result.group())
result = re.match(regex,content)
print(result)
result = re.split(r"[,!。]",content)
print(result)
三、基礎語法
3.1、跳脫字元
使用正規表示式去檢索某些特殊字元的時候,需要用到跳脫字元,否則檢索不到結果,甚至會報錯;在 Python 中,\ 具有轉義的意思,會對緊隨其後的字元進行轉義,如果我們想使用普通的 \ ,需要在使用一個 \ 對它進行轉義。
import re
content = "abc$def(123(456))"
regex = "\(456"
result = re.findall(regex,content)
print(result)
result = re.match(regex,content)
print(result)
需要用到轉義符號的常見字元如下:. * + ( ) $ / \ ? [ ] ^
3.2、字元匹配符
字元匹配符 | 含義 | 例項 | 解釋 |
---|---|---|---|
[] |
可接收的字元列表 | [abc] | a、b、c 中的任意 1 個字元 |
[^] |
不可接收的字元列表 | [^abc] | 除 a、b、c 之外的任意 1 個字元 包括數字和特殊符號 |
- |
連字元 | a-z | 任意一個小寫字母 |
import re
content = "abc123def4567AbC"
result = re.findall("[abc]",content)
print(result)
result = re.findall("[^abc]",content)
print(result)
result = re.findall("[a-z]",content)
print(result)
3.3、元字元
元字元 | 含義 |
---|---|
. |
匹配單個除換行符以外的任意字元 |
\d |
匹配 0~9 任意一個數字 |
\D |
匹配單個任意非數字字元 |
\s |
匹配任意空白字元 |
\S |
匹配任意不是空白符的字元 |
\w |
匹配字母或數字或下劃線的任意字元 |
\W |
匹配任意不是字母、數字、下劃線的字元 |
import re
content = "abc123def4567AbC"
result = re.findall("\\d\\d\\d",content)
print(result)
result = re.findall(r"\d\w",content)
print(result)
元字元的大寫表示不匹配;
3.4、重複限定符
重複限定符用於指定其前面的字元和組合項連續出現多少次。
重複限定符 | 意義 |
---|---|
? |
0 次 或 1 次 |
* |
0 次 或 多次 |
+ |
1 次 或 多次 |
{n} |
正好出現 n 次 |
{n,} |
至少出現 n 次 |
{n,m} |
出現 n 次 至 m 次 |
import re
content = "abc123def4567AbC89d115200a1"
resutl = re.findall(r"\d{3,5}",content)
print(resutl)
result = re.findall(r"\d+",content)
print(result)
3.5、定位符
定位符,用來指定要匹配的字串出現的位置。
定位符 | 含義 |
---|---|
^ | 指定起始字元 |
$ | 指定結束字元 |
\b | 匹配目標字串的邊界, 邊界指的是字串間有空格,或者目標字串的結束位置 |
\B | 匹配非單詞邊界 |
import re
content = "abc123 def4567abc123abc abc89 d115200 a1abc"
result = re.findall("^abc",content)
print(result)
result = re.findall("abc$",content)
print(result)
result = re.findall(r"abc\b",content)
print(result)
result = re.findall("^ab\B",content)
print(result)
3.6、選擇匹配符
正規表示式用符號 | 來表示或,也叫做分支條件,當滿足正則表達裡的分支條件的任何一種條件時,都會當成匹配成功。
import re
content = "你好啊,小櫻同學,歡迎你加入小櫻班,從現在開始你就是我的朋友啊,小櫻同志,請多多關照。"
regex = "小櫻同學|小櫻同志"
result = re.findall(regex,content)
print(result)
3.6、分組組合
重複限定符是作用在與它相鄰的最左邊的一個字元。正規表示式中可以使用小括號 () 來做分組,也就是括號中的內容會作為一個整體。
3.6.1、捕獲分組
我們可以使用 group() 方法匹配物件方法,從一個分組中獲取匹配的文字。正規表示式字串中的第一對括號是第 1 組,第二對括號是第 2 組,依次類推。向 group() 匹配物件方法傳入整數就可以取得匹配文字的不同部分。向 group() 傳入 0 或者不傳入引數,將返回這個匹配的文字。
如果想要一次就獲取所有的分組,我們可以使用 groups() 方法。
捕獲分組 | 說明 |
---|---|
(pattern) |
非命名捕獲。捕獲匹配的子字串。編號為零的第一個捕獲是由整個正規表示式模式匹配的文字,其它捕獲結果則根據左括號的順序從 1 開始自動編號。 |
(P<name>pattern) |
命名捕獲。將匹配的子字串捕獲到一個組名稱或編號名稱中。用於 name 的字串不能包含任何標點符號,並且不能以數字開頭。可以使用單引號替代尖括號。 |
import re
content = "我是小櫻,我的身份證明是37028419860401232X"
regex = r"\d{6}(\d{4})(\d{2})(\d{2})\d{3}[\dX]"
result = re.search(regex,content)
year = result.group(1)
month = result.group(2)
day = result.group(3)
print(result.group(0))
print(f"{year}-{month}-{day}")
import re
content = "我是小櫻,我的身份證明是37028419860401232X"
regex = r"\d{6}(?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2})\d{3}[\d|X]"
result = re.search(regex,content)
year = result.group("year")
month = result.group("month")
day = result.group("day")
print(result.group(0))
print(f"{year}-{month}-{day}")
3.6.2、非捕獲分組
非捕獲分組 | 說明 |
---|---|
(?:pattern) |
匹配 pattern 但不捕獲該匹配的子表示式,即它是一個非捕獲匹配,不儲存以後使用的匹配。 例如:"小櫻(?:同學|同志)" 等價於 "小櫻同學|小櫻同志" |
(?=pattern) |
它是一個非捕獲匹配。 例如:"Harmony(?=2|3)" 匹配 "Harmony2" 中的 "Harmony",但不匹配 "Harmony1" 中的 "Harmony" |
(?!pattern) |
該表示式匹配不處於匹配 pattern 的字串的起始點的搜尋字串。它是一個非捕獲匹配。 例如:"Harmony(?=2|3)" 匹配 "Harmony1" 中的 "Harmony",但不匹配 "Harmony2" 中的 "Harmony" |
import re
content = "你好啊,小櫻同學,歡迎你加入小櫻班,從現在開始你就是我的朋友啊,小櫻同志,請多多關照。"
regex = "小櫻(?:同學|同志)"
result = re.findall(regex,content)
print(result)
regex = "小櫻(?=同學|同志)"
result = re.findall(regex,content)
print(result)
regex = "小櫻(?!同學|同志)"
result = re.findall(regex,content)
print(result)
3.7、非貪婪匹配
當 ? 元字元緊隨任何其它限定符 (*、+、?、{n}、{n,}、{n,m})之後,匹配模式是 “非貪婪匹配”。非貪婪匹配搜尋到、儘可能短的字串。而預設的貪婪匹配搜尋到的儘可能長的字串。
import re
content = "abc111111abc"
# 貪婪匹配
result = re.findall(r"\d{3,5}",content)
print(result)
# 非貪婪匹配
result = re.findall(r"\d{3,5}?",content)
print(result)