1. 程式人生 > >python 3.6 正則表示式的應用(附例項程式碼)

python 3.6 正則表示式的應用(附例項程式碼)

python 3.6 正則表示式的應用

正則表示式用於搜尋、替換和解析字串。正則表示式遵循一定的語法規則,使用非常靈活,功能強大。使用正則表示式編寫一些邏輯驗證非常方便,例如電子郵件地址格式的驗證。Python提供了re模組實現正則表示式的驗證。

正則表示式簡介

正則表示式是用於文字匹配的工具,它在源字串中查詢與給定的正則表示式相匹配的部分。一個正則表示式是由字母、數字和特殊字元(括號、星號、問號等)組成。正則表示式中有許多特殊的字元,這些特殊字元是構成正則表示式的要素。

其中,匹配符“[]”可以指定一個匹配範圍,
例如“[ok]”將匹配包含“o”或“k”的字元。同時“[]”可以與\w、\s、\d等標記等價。例如,[0
-9a-zA-Z_]等價於\w,[^0-9]等價於\D。

注意 \^與[\^m]中的“\^”的含義並不相同,後者的“\^”表示“除了……”的意思。

如果要匹配電話號碼,需要形如“\d\d\d\d-\d\d\d\d\d\d\d”這樣的正則表示式。其中出現了11次“\d”,表達方式煩瑣。而且某些地區的電話號碼是8位數字,區號也有可能是3位或4位數字,因此這個正則表示式就不能滿足要求了。

正則表示式作為一門小型的語言,還提供了對錶達式的一部分進行重複處理的功能。例如,“*”可以對正則表示式的某個部分重複匹配多次。這種匹配符號稱為限定符。
下表列出了正則表示式中常用的限定符:


利用{}可以控制字元重複的次數。例如,\d{1,4}表示1~3位數字。前面提到的電話號碼,可以採用如下的正則表示式。

\d{3}-\d{8} | \d{4}-\d{7}


【程式碼說明】該表示式匹配區號為3位的8位數電話號碼或區號為4位的7位數電話號碼。

注意 “(”和“)”是正則表示式中的特殊字元,如果要把它們作為普通字元處理,需要在前面新增轉義字元“\”。

注意 表中的(?P…)和(?P=name)是Python中的寫法,其他的符號在各種程式語言中都是通用的。

使用re模組處理正則表示式

Python的re模組具有正則表示式匹配的功能。re模組提供了一些根據正則表示式進行查詢、替換、分隔字串的函式,這些函式使用一個正則表示式作為第一個引數。
re模組常用的函式如下所示:

注意 函式match()必須從字串的第0個索引位置處開始搜尋。如果第0個索引位置的字元不匹配,match()的匹配失敗。

re模組的一些函式中都有一個flags引數,該引數用於設定匹配的附加選項。例如,是否忽略大小寫、是否支援多行匹配等。
下表列出了re模組的規則選項。



re模組定義了一些常量來表示這些選項,使用前導符“re.”加選項的簡寫或名稱的方式表示某個常量。例如,re.I或re.IGNORECASE表示忽略大小寫。

正則表示式中有3種間隔符號:“^”、“$”和“\b”。
“^”匹配字串首部的子串,“$”匹配結束部分的子串,而“\b”用於分隔單詞。

下面這段程式碼展示了這些間隔符在Python中的使用。

import re
# ^與$的使用
string = "HELLO WORLD"
print(re.findall(r"^hello", string))
print(re.findall(r"^hello", string, re.I))
print(re.findall("WORLD$", string))
print(re.findall(r"WORLD$", string))
print(re.findall(r"WORLD$", string, re.I))
print(re.findall(r"\b\w+\b", string))

【程式碼說明】

  • 第4行程式碼匹配以“hello”開始的字串。由於變數s中的“HELLO”採用的是大寫,所有匹配失敗。輸出結果為“[]”。
  • 第5行程式碼添加了輔助引數flags,re.I表示匹配時忽略大小寫。輸出結果為“[‘HELLO’]”。
  • 第6行程式碼匹配以“WORLD”結尾的字串。輸出結果為“[‘WORLD’]”。
  • 第7行程式碼匹配以“WORLD”結尾的字串,並忽略大小寫。輸出結果為“[‘WORLD’]”。
  • 第8行程式碼匹配每個英文單詞。輸出結果為“[‘HELLO’,’WORLD’]”。

在python中可以使用函式replace()實現字串的替換,同樣可以使用re模組的sub()實現替換的功能。
下面這段程式碼演示了sub()替換字串的功能。

import re
# 使用sub()實現字串的替換
string = "hello world"
print(re.sub("hello", "hi", string))
print(re.sub("hello", "hi", string[-4:]))
print(re.sub("world", "China", string[-5:]))

【程式碼說明】

  • 第4行程式碼的輸出結果為“hi world”。
  • 第5行程式碼在分片s[-4:]範圍內替換“hello”,即在字串“orld”中替換“hello”。由於沒有找到匹配的子串,所有sub()返回s[-4:]。輸出結果為“orld”。
  • 第6行程式碼在分片s[-5:]範圍內替換“world”,即把字串“world”替換為“China”。輸出結果為“China”。

注意 sub()先建立變數s的拷貝,然後在拷貝中替換字串,並不會改變變數s的內容。

subn()的功能與sub()相同,但是多返回1個值,即匹配後的替換次數。
下面這段程式碼演示了subn()對字串的替換以及正則表示式中特殊字元的使用。

import re
# 特殊字元的使用
string = "你好 WORLD2"
print("匹配字母數字:" + re.sub(r"\w", "hi", string))
print("替換次數:" + str(re.subn(r"\w", "hi", string)))
print("匹配非字母數字的字元:" + re.sub(r"\W", "hi", string))
print("替換次數:" + str(re.subn(r"\W", "hi", string)[1]))
print("匹配空白字元:" + re.sub(r"\s", "*", string))
print("替換次數:" + str(re.subn(r"\s", "*", string)))
print("匹配非空白字元:" + re.sub(r"\S", "#", string))
print("替換次數:" + str(re.subn(r"\S", "#", string)[1]))
print("匹配數字:" + re.sub(r"\d", "2.0", string))
print("替換次數:" + str(re.subn(r"\d", "2.0", string)[1]))
print("匹配非數字:" + re.sub(r"\D", "&", string))
print("替換次數:" + str(re.subn(r"\D", "&", string)[1]))
print("匹配任意字元:" + re.sub(r".", "%", string))
print("替換次數:" + str(re.subn(r".", "%", string)[1]))

【程式碼說明】

  • 第4行程式碼,“\w”並不能匹配漢字。
  • 第5行程式碼輸出替換次數。替換次數存放在subn()返回元組的第2個元素中。
  • 第6行程式碼替換非字母、數字、下劃線的字元。
  • 第7行程式碼,漢字“你好”和後面的空格被替換為5個“hi”,每個漢字佔2個字元。
  • 第8行程式碼匹配空白字元,空格、製表符等都屬於空白字元。
  • 第9行程式碼,由於只有一個空格,所以替換次數為1。
  • 第10行程式碼替換非空格字元。
  • 第11行程式碼,除空格外字串共佔用了10個字元。
  • 第12行程式碼替換數字。
  • 第13行程式碼把數字2替換為“2.0”。
  • 第14行程式碼替換每個英文字元。
  • 第15行程式碼替換了10個非數字字元。
  • 第16行程式碼,“.”替換任意字元。
  • 第17行程式碼,所有11個字元均被替換。

正則表示式的解析非常費時,如果多次使用同一規則匹配字串,可以使用compile()進行預編譯,compile函式返回1個pattern物件。該物件擁有一系列方法用於查詢、替換或擴充套件字串,從而提高字串的匹配速度。下表列出了pattern物件的屬性和方法。

下面這段程式碼在1個字串中查詢多個數字,使用compile()提高查詢的效率。

import re
# compile()預編譯
string = "1abc23def45"
pat = re.compile(r"\d+")
print(pat.findall(string))
print(pat.pattern)

【程式碼說明】

  • 第4行程式碼返回1個正則表示式物件p,匹配變數s中的數字。
  • 第5行程式碼呼叫p的findall()方法,匹配的結果存放在列表中。輸出結果為“[‘1’,’23’,’45’]”。
  • 第6行程式碼輸出當前使用的正則表示式。輸出結果為“\d+”。

函式compile()通常與match()、search()、group()一起使用,對含有分組的正則表示式進行解析。正則表示式的分組從左往右開始計數,第1個出現的圓括號標記為第1組,依次類推。此外還有0號組,0號組用於儲存匹配整個正則表示式的結果。match()和search()將返回1個match物件,match物件提供了一系列的方法和屬性來管理匹配的結果。
下表列出了match物件的方法和屬性。

下面這段程式碼演示了對正則表示式分組的解析。

import re
# 分組
pat = re.compile(r"(abc)\1")
mat = pat.match("abcabcabc")
print(mat.group(0))
print(mat.group(1))
print(mat.group())

pat = re.compile(r"(?P<one>abc)(?P=one)")
mat = pat.search("abcabcabc")
print(mat.group("one"))
print(mat.groupdict().keys())
print(mat.groupdict().values())
print(mat.re.pattern)

【程式碼說明】

  • 第3行程式碼定義了1個分組“(abc)”,在後面使用“\1”再次呼叫該分組。即compile()返回1個包含2個分組的正則表示式物件p。
  • 第4行程式碼,p.match()對字串“abcabcab”進行搜尋,返回1個match物件m。
  • 第5行程式碼呼叫match物件的group(0)方法,匹配0號組。輸出結果為“abcabc”。
  • 第6行程式碼呼叫match物件的group(1)方法,匹配1號組。輸出結果為“abc”。
  • 第7行程式碼,預設情況下,返回分組0的結果。輸出結果為“abcabc”。
  • 第9行程式碼,給分組命名,“?P”中的“one”表示分組的名稱。“(?P=one)”呼叫分組“one”,相當於“\1”。
  • 第11行程式碼輸出分組“one”的結果。輸出結果為“abc”。
  • 第12行程式碼獲取正則表示式中分組的名稱。輸出結果為“[‘one’]”。
  • 第13行程式碼獲取正則表示式中分組的內容。輸出結果為“[‘abc’]”。
  • 第13行程式碼獲取正則表示式中分組的內容。輸出結果為“[‘abc’]”。
  • 第14行程式碼獲取當前使用的正則表示式。輸出結果為“(?Pabc)(?P=one)”。

如果使用match()匹配的源字串“abcabcabc”改為“bcabcabc”,則Python將提示如下錯誤。

AttributeError: 'NoneType' object has no attribute 'group'


這種情況可以用search()替換match(),search()可以匹配出正確的結果。