Python 正規表示式教程
-
match()
函式 -
search()
函式 - 編譯正規表示式
-
標誌位
flags
- 檢查允許的字元
- 搜尋和替換
-
findall()
函式 -
finditer()
函式 -
split()
函式 -
Basic patterns of
re
的基本模式 - 重複情形
- 非貪婪匹配
- 正規表示式中的特殊字元和轉義
-
轉義函式
escape
-
group()
方法
在本教程中,我們將學習正規表示式以及 Python re
中模組中定義的正規表示式操作。re
是 Python 的標準庫,它支援正規表示式的匹配操作。
Python 中的正規表示式是一組字元或序列,用於使用正式語法將字串與另一個模式匹配。你可以將正規表示式視為嵌入在 python 中的小型程式語言。
你可以使用正規表示式來定義一些規則,然後使用這些規則從你希望與模式匹配的給定字串中建立可能的字串。Python 中的正規表示式被解釋為一組指令。
match()
函式
你可以使用 match()
函式將 RE 模式與給定字串來匹配。match()
函式也包含了標誌,標誌定義正規表示式的行為,它可以有不同的值,後續我們在本教程會繼續講到。
以下是 Python 中 match()
函式的語法:
re.match(pattern, string, flags)
它有三個引數,
pattern
是要匹配的正規表示式模式string
是與正規表示式匹配的給定字串flags
用於更改正規表示式的行為,這是個可選項
如果匹配成功就返回 Match
物件,否則返回 NONE
。匹配物件 Match
還有兩個主要方法,即 group(num)
和 group()
。可以使用這些方法來分別返回匹配的特定子序列和所有子序列。
使用 match
函式
我們來看下如何使用 match
函式,
import re
strTest = "Hello Python Programming"
mobj = re.match(r"hello", strTest, re.I)
print(mobj.group())
第一行如何匯入了 re
模組,
第二行是我們需要匹配的字串 Hello Python Programming
,
第三行是需要將該字串跟匹配模式 r"Hello"
比較,並且 re.I
指定的匹配模式是忽略大小寫。最終匹配的結果賦值給 mobj
第四行將匹配的結果給列印出來,結果如下,
Hello
在此示例中,使用字首 r
來表示字串是原始字串。在原始字串中,在使用轉義序列時不需要寫雙斜槓,例如,如果你想要一個反斜槓,那麼你只需要一個\
,而不用像普通字串那樣的雙反斜槓\\
。
match
函式與常規字串
我們來看一個不用原始字串而用常規字串來做匹配的例子,
import re
str = "\\tHello Python Programming"
mobj = re.match("\\thello", str, re.I) #no match
str = "\tHello Python Programming"
mobj = re.match("\\thello", str, re.I) #\thello is matching
search()
函式
你可以使用 search()
函式搜尋給定字串中的正規表示式匹配模式。search
有三個輸入引數,匹配模式,給定字串以及可選的匹配行為選項 flags
以下是 Python 中 search
函式的語法,
re.search(pattern, string, flags)
我們來看具體的 search()
函式使用例項,
import re
str = "Hello Python Programming"
sobj = re.search(r"programming", str, re.I)
print(sobj.group())
Programming
在此程式碼中,我們來搜尋給定字串中是否存在 programming
,search
函式搜尋整個字串。搜尋 search
和匹配 match
之間的區別在於 match
函式只檢查字串的開頭,而 search
在整個字串中搜尋。
在字串開頭搜尋
如果你想在字串的開頭搜尋,那麼可以使用^
。來看下例,
import re
str = "Hello Python Programming"
sobj = re.search(r"^programming", str, re.I)
print(sobj.group()) #no match is found
sobj = re.search(r"^hello", str, re.I)
print(sobj.group()) #matching: Hello
這裡,^
的意思是隻在字串的開頭進行搜尋,假如開頭不匹配的話,就返回 None
,而不管字串後續中有沒有再匹配到。
在字串結尾搜尋
你也可以在給定字串的末尾搜尋,通過在模式後面加 $
來限定。來看這個例子,
import re
str = "Hello Python Programming"
sobj = re.search(r"programming$", str, re.I)
print(sobj.group()) #matching: Programming
sobj = re.search(r"hello$", str, re.I)
print(sobj.group()) #no match found
編譯正規表示式
Python 中的正規表示式在編譯時將轉換為模式,這些模式實際上是包含不同功能的模式物件,以執行不同的任務,包括搜尋,匹配和替換等。
編譯模式後,你可以稍後在程式中使用該模式。
使用預編譯的模式
在下面的例子中,被編譯的模式 r"\d"
意思是在字串中的第一個數字。當該模式後續跟 search
一起使用的時候,它搜尋輸入字串中的一個數字;同樣的,你也可以用這個模式跟 match
搭配來找到給定字串中的匹配。
import re
compPat = re.compile(r"(\d)")
sobj = compPat.search("Lalalala 123")
print(mobj.group())
mobj = compPat.match("234Lalalala 123456789")
print(mobj.group())
1
2
標誌位 flags
你可以使用標誌位 flags
來改變正規表示式的行為。在正則函式中,標誌位是可選項。你可以通過兩種不同的方式來使用標誌,即使用關鍵字 flags
併為其分配標誌值或直接寫入標誌位的值。你可以設定多個標誌位,這可以通過使用按位或運算|
符來完成。
下表列出了正規表示式的一些常用標誌,
標誌位 | 說明 |
---|---|
re.I |
在匹配時忽略字串和模式的大小寫 |
re.L |
匹配 {\w \W \b \B} 跟本地語言相關。不推薦使用 |
re.M |
$ 匹配行末尾,而不是字串末尾,同理^ 匹配行開頭而不是字串開頭 |
re.S |
. 匹配任何字元,也包括新的一行 |
re.U |
使用 Unicode 字符集 |
re.X |
忽略各種空格以及以 # 開頭的註釋,這使得長匹配模式可以分行來寫,提高了可讀性 |
使用多個標誌位
我們用下面的程式碼來演示如何來使用多個標誌位來修改正規表示式的行為結果,它們是通過或邏輯符|
分開的。
import re
s = re.search("L", "Hello")
print(s) #Output: None, L is there but in small letter and we didn't use flags
s = re.search("L", "Hello", re.I)
print(s) #Output: 1
s = re.search("L", "^Hello", re.I | re.M)
print(s) #Output: 1, searching will be made from the start of line and case is ignored
檢查允許的字元
你可以檢查一個特定的字串中是否是否含有特性的字符集。
定義函式並檢查允許的字元
在下面的例子中,我們定義了一個函式,並使用預編譯模式來檢查某些字元是否在給定的字串中,
import re
def check(str):
s = re.compile(r'[^A-Z]')
str = s.search(str)
return not bool(str)
print(check("HELLOPYTHON")) # 輸出: True
print(check("hellopython")) # 輸出: False
在此函式中,模式 r'[^A-Z]'
被編譯並使用它來搜尋在呼叫名為 check
的函式中傳遞的字串。此函式實際檢查傳遞的字串是否包含大寫字母。類似地,你可以看到當你傳遞的字串中只含有小寫字母時返回 False
。
搜尋和替換
re
模組提供了一個 sub
函式來替換給定字串 string
中出現的所有符合 pattern
匹配模式的情況,用來替換的字串是 repl
。你可以通過 count
關鍵字引數指定最大的替換次數,假如 count
沒有給定的話,那就沒有最大替換次數限制。sub
函式返回了一個新的字串。
以下是 sub
函式的語法,
re.sub(pattern, repl, string, count = 0)
sub
函式舉例
下面的例子中,sub
函式將整個字串用新的字串替換掉了,
import re
s = "Playing 4 hours a day"
obj = re.sub(r'^.*$',"Working",s)
print(obj)
Working
這裡,模式 r'^.*$
中,^
和 $
意思是從開頭到結尾,.*
意思是匹配字串中的任意字元,它們結合起來就是匹配從開頭到結尾的任意字元。"Working"
將來替換整個字串 s
。
使用 sub
函式來刪除字串中的所有數字
下面的例子中,使用 sub
函式來刪除給定字串中的數字,你需要用\d
來匹配數字。
import re
s = "768 Working 2343 789 five 234 656 hours 324 4646 a 345 day"
obj = re.sub(r'\d',"",s)
print(obj)
Working five hours a day
類似的,你可以來刪除字串中的字母,用 \D
來匹配所有的字母。
import re
s = "768 Working 2343 789 five 234 656 hours 324 4646 a 345 day"
obj = re.sub(r'\D',"",s)
print(obj)
76823437892346563244646345
findall()
函式
The findall
函式返回與模式匹配的所有字串組成的列表。search
和 findall
函式之間的區別在於 findall
查詢所有匹配項,而 search
只查詢第一個匹配項。findall
函式查詢出非重疊的匹配並將其組成列表來返回。
以下是 findall
函式的語法,
findall(pattern, string, flags)
這裡,pattern
是正則表達,string
是給定字串,flags
是前面已經介紹的標誌位。
查詢所有的非重疊的匹配
下面的例子中,findall
找出所有非重疊的匹配,
import re
str = "Working 6 hours a day. Studying 4 hours a day."
mobj = re.findall(r'[0-9]', str)
print(mobj)
['6', '4']
r'[0-9]'
的意思是匹配所有的數字,最終結果 6, 4
以列表的形式被返回賦值給 mobj
。
findall
查詢檔案的內容
你還可以使用 findall
在檔案中查詢。當你使用 findall
來查詢檔案內容時,它將返回檔案中所有匹配的字串的列表,我們可以使用檔案的 read()
方法來讀取檔案中的全部內容,因此你不必來使用迴圈。下面我們具體通過例子來解釋,
import re
file = open('asd.txt', 'r')
mobj = re.findall(r'arg.', file.read())
print(mobj)
file.close()
['arg,', 'arg,', 'arg,', 'argv', 'argv', 'argv']
本例中,檔案通過只讀模式開啟,然後匹配模式 r'arg.'
用來匹配四個字元中其中前三個字元是 arg
而第四個字元任意的情況。所有的匹配字串通過列表來返回結果。
finditer()
函式
finditer
函式可用於在字串中查詢正規表示式模式並將匹配的字串以及字串的位置返回。
以下是 finditer
函式的語法:
finditer(pattern, string, flags)
遍歷所有的匹配
findall
和 finditer
之間唯一的區別是 finditer
返回索引以及匹配的字串。在下面的程式碼中,finditer
用於查詢匹配字串的位置,而後通過 for
迴圈來在遍歷所有的匹配(匹配字串)。
import re
str = "Working 6 hours a day. Studying 4 hours a day."
pat = r'[0-9]'
for mobj in re.finditer(pat, str):
s = mobj.start()
e = mobj.end()
g = mobj.group()
print('{} found at location [{},{}]'.format(g, s, e))
6 found at location [8,9]
4 found at location [32,33]
split()
函式
split
函式用於拆分字串,以下是 split 函式的語法,
split(patter, string, maxsplit=0, flags=0)
這裡 maxsplit
是最多的拆分次數,假如能夠拆分的次數大於 maxsplit
那麼剩餘的字串將作為列表中的最後一個元素。maxsplit
的預設值是 0,意思是可以無限拆分。
拆分一個字串
我們可以通過 split
來拆分字串,下面的例子中,字串根據給定的模式以及最大拆分的數量來拆分。
import re
str = "Birds fly high in the sky for ever"
mobj = re.split('\s+', str, 5)
print(mobj)
['Birds', 'fly', 'high', 'in', 'the', 'sky for ever']
本例中,模式 \s
用來匹配所有的空白字元,它等效於各種空白字元的集合,包括空格,製表符,回車等,具體如 [ \t\n\r\f\v]
。所以你可以通過它將各個拆分開來。這裡的最大拆分次數是 5
,所以結果列表中有 6
個元素,最後一個元素是最後一次拆分後剩下的所有的字串。
Basic patterns of re
的基本模式
正規表示式可以指定與給定字串進行比較的模式。以下是正規表示式的基本模式,
模式 | 描述 |
---|---|
^ |
在字串開頭匹配 |
$ |
在字串的結尾處匹配 |
. |
匹配任意一個字元(不包括換行符) |
[...] |
匹配括號內的單個字元 |
[^...] |
匹配不在括號中的單個字元 |
* |
給定字串中出現 0 次或更多次 |
+ |
給定字串中出現 1 次或多次前面的 |
? |
給定字串中出現 0 次或 1 次 |
{n} |
匹配給定字串中出現次數為 n |
{n,} |
匹配給定字串中出現次數為 n 次或多次 |
{n,m} |
匹配給定字串中的出現次數為至少 n 個,最多 m 個 |
`a | b` |
(re) |
此模式用於對正規表示式進行分組,它將記住匹配的文字,也叫反身引入 |
(?imx) |
它將暫時在 RE 上切換 i 或 m 或 x。使用括號時,只會影響括號區域 |
(?-imx) |
它會暫時關閉 RE 中的 i 或 m 或 x。使用括號時,只會影響括號區域 |
(?: re) |
此模式用於對正規表示式進行分組,但不會記住匹配的文字 |
(?imx: re) |
它將臨時在括號內的 RE 或 i 或 RE 中切換 |
(?-imx: re) |
它會在括號內暫時切換 i 或 m 或 x 中的 RE |
(?#...) |
這是一個評論 |
(?= re) |
它用於通過使用模式指定位置。它沒有任何範圍 |
(?! re) |
它用於通過使用模式否定來指定位置。它沒有任何範圍 |
(?> re) |
此模式用於匹配獨立模式 |
\w |
此模式用於匹配單詞 |
\W |
此模式用於匹配非單詞 |
\s |
它將匹配空格。\s 等於 [ \t\n\r\f] |
\S |
它將匹配非空格 |
\d |
\d 等於 [0-9]。它匹配字串中的數字 |
\D |
匹配非數字 |
\A |
匹配字串的開頭 |
\Z |
匹配字串的結尾。如果有任何換行符,它將在換行符之前匹配 |
\z |
匹配字串的結尾 |
\G |
\G 用於匹配最後一次匹配結束的點 |
\b |
匹配在開頭或者結尾的空字元 |
\B |
匹配不在開頭或者結尾的空字元 |
\n, \t, etc. |
\n 用於匹配換行符,\t 將匹配分隔符 |
\1...\9 |
匹配第 n 個子表示式(已分組) |
\10 |
\ 10 通常匹配第 n 個子表示式(已分組),如果匹配已經完成。如果匹配尚未完成\ 10 將提供字元程式碼的八進位制表示 |
重複情形
下面的列表中列出了匹配當中的重複情形以及它們的具體說明。
舉例 | 說明 |
---|---|
ab? |
匹配 a 或者 ab |
ab* |
匹配 a 或者 a 後面接任意個 b ,比如 ab , abb … |
ab+ |
匹配 a 以及至少一個 b |
\d{2} |
匹配兩個數字 |
\d{2,} |
匹配兩個或多個數字 |
\d{2,4} |
匹配 2 到 4 個數字 |
非貪婪匹配
在正規表示式在,重複一般意義上都是貪婪的,也就是它試圖儘量多的去匹配最大的重複。限定符 *
, +
及 ?
是貪婪限定符,當你使用*
時,它會進行貪婪匹配,會匹配字串中儘量多的字元。比如下面的例子,
import re
mobj = re.match(r'.*', "Birds fly high in sky")
print(mobj.group())
Birds fly high in the sky
你能看出來,整個字串都被匹配了。
當你一起使用 ?
和 .+
時,就得到了一個非貪婪匹配模式 .+?
,它會盡量少的去匹配字串中的內容。
import re
mobj = re.match(r'.*', "Birds fly high in sky")
print(mobj.group())
結果就只有一個字元,
B
正規表示式中的特殊字元和轉義
re
模組中的特殊字元以 \
為開始。比如,\A
匹配字串的開頭。在上面的列表當中,我們已經具體介紹了這些特殊字元,我們將用例子來解釋它們的具體用法。
import re
str = "Birds fly high in the sky"
# \A
mobj = re.match(r'\Ab', str, re.I) #OUTPUT: B, here \A will match at beginning only.
#\d
mobj = re.match(r'\d', "4 birds are flying") #OUTPUT: 4
#\s
mobj = re.split('\s+', "birds fly high in the sky", 1) #OUTPUT: ['Birds', 'fly']
轉義函式 escape
escape
函式用來轉義字串中的字元,ASCII 字母、數字以及下劃線 _
不會被轉義。下面是 escape
函式的語法,
escape(pattern)
在下面的例子中,字串 www.python.com
被傳入到 escape
函式,其中的 .
是一個特殊的元字元,將會被轉義成\.
。
print(re.escape('www.python.com'))
www\.python\.com
一般而言,特殊的元字元會通過在前面加反斜槓\
來轉義。
轉義特殊字元
比如說像括號 [
和 ]
這樣的字元,在正規表示式中具有特殊的意義。我們先看一個例子,
import re
mobj = re.search(r'[a]', '[a]b')
print(mobj.group())
a
這裡,很明顯,[
和 ]
沒有被匹配到,因為它們在正規表示式中的含義是匹配該括號裡面的一個字元。假如你想要匹配 [
和 ]
的話,你需要在它們前面加\
。
import re
mobj = re.search(r'\[a\]', '[a]b')
print(mobj.group())
[a]b
group()
方法
group
方法用來返回一個或多個被查詢到的匹配的子匹配字串,它的引用方法如下,
group(index)
If you have a single argument in group function, the result will be a single string but when you have more than one arguments, then the result will be a tuple (containing one item per argument).
When there is no argument, by default argument will be zero and it will return the entire match.
When the argument groupN
is zero, the return value will be entire matching string.
When you specify the group number or argument as a negative value or a value larger than the number of groups in pattern then IndexError
exception will occur.
Consider the code below in which there is no argument in group
function which is equivalent to group(0)
.
import re
str = "Working 6 hours a day"
mobj = re.match(r'^.*', str)
print(mobj.group())
Working 6 hours a day
Here group()
is used and you have the entire matched string.
Picking parts of matching texts
In the following example, group
function is used with arguments to pick up matching groups:
import re
a = re.compile('(p(q)r)s')
b = a.match('pqrs')
print(b.group(0))
print(b.group(1))
print(b.group(2))
pqrs
pqr
q
Here group(0)
returns the entire match. group(1)
will return the first match which is pqr
and group(2)
will return the second match which is q
.
Named groups
Using named groups you can create a capturing group. This group can be referred by the name then. Consider the example below:
import re
mobj = re.search(r'Hi (?P<name>\w+)', 'Hi Roger')
print(mobj.group('name'))
Roger
Non-capturing groups
Non-capturing group can be created using ?:
. Non-capturing group is used when you do not want the content of the group.
import re
mobj = re.match("(?:[pqr])+", "pqr")
print(mobj.groups())
()
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn