跳轉到內容

Python 程式設計/正則表示式

來自華夏公益教科書


Python 包含一個用於在字串上使用正則表示式的模組。有關編寫正則表示式和不特定於 Python 的語法的更多資訊,請參閱正則表示式華夏公益教科書。Python 的正則表示式語法類似於Perl 的

要開始在您的 Python 指令碼中使用正則表示式,請匯入“re”模組

import re

Python 中的正則表示式函式一覽

import re
if re.search("l+","Hello"):        print(1) # Substring match suffices
if not re.match("ell.","Hello"):   print(2) # The beginning of the string has to match
if re.match(".el","Hello"):        print(3)
if re.match("he..o","Hello",re.I): print(4) # Case-insensitive match
print(re.sub("l+", "l", "Hello"))           # Prints "Helo"; replacement AKA substitution
print(re.sub(r"(.*)\1", r"\1", "HeyHey"))   # Prints "Hey"; backreference
print(re.sub("EY", "ey", "HEy", flags=re.I))# Prints "Hey"; case-insensitive sub
print(re.sub(r"(?i)EY", r"ey", "HEy"))      # Prints "Hey"; case-insensitive sub
for match in re.findall("l+.", "Hello Dolly"):
  print(match)                              # Prints "llo" and then "lly"
for match in re.findall("e(l+.)", "Hello Dolly"):
  print(match)                              # Prints "llo"; match picks group 1
for match in re.findall("(l+)(.)", "Hello Dolly"):
  print(match[0], match[1])                 # The groups end up as items in a tuple
match = re.match("(Hello|Hi) (Tom|Thom)","Hello Tom Bombadil")
if match:                                 # Equivalent to if match is not None
  print(match.group(0))                   # Prints the whole match disregarding groups
  print(match.group(1) + match.group(2))  # Prints "HelloTom"

匹配和搜尋

[編輯 | 編輯原始碼]

正則表示式的最常見用途之一是提取字串的一部分或測試字串中是否存在模式。Python 提供了幾個函式來執行此操作。

match 和 search 函式的功能基本相同,不同的是,match 函式只有在模式匹配要搜尋的字串的開頭時才會返回結果,而 search 會在字串中的任何位置找到匹配項。

>>> import re
>>> foo = re.compile(r'foo(.{,5})bar', re.I+re.S)
>>> st1 = 'Foo, Bar, Baz'
>>> st2 = '2. foo is bar'
>>> search1 = foo.search(st1)
>>> search2 = foo.search(st2)
>>> match1 = foo.match(st1)
>>> match2 = foo.match(st2)

在此示例中,match2 將為None,因為字串st2 不以給定模式開頭。其他 3 個結果將是 Match 物件(見下文)。

您也可以在不編譯正則表示式的情況下進行匹配和搜尋

>>> search3 = re.search('oo.*ba', st1, re.I)

這裡我們使用 re 模組的 search 函式,而不是模式物件的 search 函式。在大多數情況下,最好先編譯表示式。並非所有 re 模組函式都支援 flags 引數,如果表示式使用不止一次,則先編譯更高效,並導致程式碼更簡潔。

編譯後的模式物件函式也有引數用於開始和結束搜尋,以在給定字串的子字串中搜索。在本節的第一個示例中,match2 沒有返回結果,因為模式不在字串的開頭,但如果我們這樣做

>>> match3 = foo.match(st2, 3)

它可以工作,因為我們告訴它從字串中的第 3 個字元開始搜尋。

如果我們要搜尋模式的多個例項怎麼辦?然後我們有兩個選擇。我們可以在迴圈中使用 search 和 match 函式的 start 和 end 位置引數,從上一個匹配物件(見下文)獲取要開始的位置,或者我們可以使用 findall 和 finditer 函式。findall 函式返回一個匹配字串的列表,對於簡單的搜尋非常有用。對於任何稍微複雜的東西,都應該使用 finditer 函式。它返回一個迭代器物件,在迴圈中使用時,會生成 Match 物件。例如

>>> str3 = 'foo, Bar Foo. BAR FoO: bar'
>>> foo.findall(str3)
[', ', '. ', ': ']
>>> for match in foo.finditer(str3):
...     match.group(1)
...
', '
'. '
': '

如果您要迭代搜尋結果,使用 finditer 函式幾乎總是更好的選擇。

匹配物件

[編輯 | 編輯原始碼]

Match 物件由 search 和 match 函式返回,幷包含有關模式匹配的資訊。

group 函式返回對應於表示式捕獲組(表示式中用()括起來的部分)的字串,或者如果未給出組號,則返回整個匹配項。使用上面定義的search1 變數

>>> search1.group()
'Foo, Bar'
>>> search1.group(1)
', '

捕獲組也可以使用特殊語法賦予字串名稱,並透過matchobj.group('name')引用。對於簡單的表示式,這是不必要的,但是對於更復雜的表示式,它非常有用。

您還可以使用 start 和 end 函式獲取匹配項或組在字串中的位置

>>> search1.start()
0
>>> search1.end()
8
>>> search1.start(1)
3
>>> search1.end(1)
5

這將分別返回整個匹配項的開始和結束位置以及第一個(在本例中也是唯一一個)捕獲組的開始和結束位置。

正則表示式的另一個用途是替換字串中的文字。要在 Python 中執行此操作,請使用 sub 函式。

sub 最多接受 3 個引數:要替換成的文字、要替換的文字以及可選的要執行的最大替換次數。與匹配和搜尋函式不同,sub 返回一個字串,它包含所給定的文字,其中進行了替換。

>>> import re
>>> mystring = 'This string has a q in it'
>>> pattern = re.compile(r'(a[n]? )(\w) ')
>>> newstring = pattern.sub(r"\1'\2' ", mystring)
>>> newstring
"This string has a 'q' in it"

這會將任何以“a”或“an”開頭的單個字母數字字元(在正則表示式語法中為 \w)括在單引號中。替換字串中的\1\2 是對錶達式中 2 個捕獲組的反向引用;這些將是 Match 物件中 group(1) 和 group(2) 的搜尋結果。

subn 函式與 sub 類似,不同的是它返回一個元組,包含結果字串和執行的替換次數。使用之前的字串和表示式

>>> subresult = pattern.subn(r"\1'\2' ", mystring)
>>> subresult
("This string has a 'q' in it", 1)

在不構建和編譯模式物件的情況下進行替換

>>> result = re.sub(r"b.*d","z","abccde")
>>> result
'aze'

split 函式根據給定的正則表示式拆分字串

>>> import re
>>> mystring = '1. First part 2. Second part 3. Third part'
>>> re.split(r'\d\.', mystring)
['', ' First part ', ' Second part ', ' Third part']

escape 函式會跳脫字元串中的所有非字母數字字元。如果需要獲取可能包含正則表示式元字元(如(.)的未知字串並從中建立正則表示式,這將很有用。

>>> re.escape(r'This text (and this) must be escaped with a "\" to use in a regexp.')
'This\\ text\\ \\(and\\ this\\)\\ must\\ be\\ escaped\\ with\\ a\\ \\"\\\\\\"\\ to\\ use\\ in\\ a\\ regexp\\.'

正則表示式中使用的不同標誌

縮寫 完整名稱 描述
re.I re.IGNORECASE 使正則表示式不區分大小寫
re.L re.LOCALE 使某些特殊序列(\w, \W, \b, \B, \s, \S)的行為取決於當前區域設定
re.M re.MULTILINE 使^$ 字元在每行的開頭和結尾處匹配,而不僅僅是在字串的開頭和結尾處匹配
re.S re.DOTALL 使. 字元匹配包括換行符在內的每個字元。
re.U re.UNICODE 使\w, \W, \b, \B, \d, \D, \s, \S 依賴於 Unicode 字元屬性
re.X re.VERBOSE 忽略空格,除非它在字元類中或前面帶有未轉義的反斜槓,並忽略#(除非它在字元類中或前面帶有未轉義的反斜槓)以及後面的所有內容到行尾,因此它可以被用作註釋。這允許使用更簡潔的正則表示式。

模式物件

[編輯 | 編輯原始碼]

如果您要在一個程式中多次使用相同的正則表示式,或者您只是想以某種方式將正則表示式分開,您應該建立一個模式物件,並在以後搜尋/替換時引用它。

要建立模式物件,請使用 compile 函式。

import re
foo = re.compile(r'foo(.{,5})bar', re.I+re.S)

第一個引數是模式,它匹配字串“foo”,後面跟著最多 5 個任意字元,然後是字串“bar”,將中間字元儲存到一個組中,這將在後面討論。第二個可選引數是修改正則表示式行為的標誌或標誌集。標誌本身只是引用正則表示式引擎使用的整數的變數。在其他語言中,這些將是常量,但 Python 沒有常量。一些正則表示式函式不支援在函式中直接定義模式時新增標誌作為引數,如果您需要任何標誌,最好使用編譯函式來建立模式物件。

表示式字串前面的 r 表示它應該被視為原始字串。在編寫正則表示式時,通常應該使用它,這樣反斜槓就會被逐字解釋,而不是必須轉義。

[編輯 | 編輯原始碼]
華夏公益教科書