天天看點

Python 進階程式設計之正規表達式(八)

作者:大資料老司機

一、概述

正規表達式(Regular Expression)是一種文本模式,用于比對字元串中的模式。它可以用于很多任務,例如文本搜尋和替換,資料提取,資料驗證等。
  • 在 Python 中,可以使用 re 子產品來支援正規表達式。正規表達式使用特殊的字元來表示不同的模式,例如 . 比對任意字元,\d 比對數字,^ 比對字元串開頭,$ 比對字元串結尾等。
  • 通過使用正規表達式,可以很友善地對字元串進行比對,搜尋和替換等操作。使用正規表達式的時候,需要先編寫一個比對模式,然後使用 re 子產品中的函數來執行實際的比對操作。

總的來說,正規表達式是一種強大且高效的文本處理工具,可以用于解決很多實際問題。

Python 進階程式設計之正規表達式(八)

二、正規表達式文法

正規表達式(Regular Expression,簡稱 regex 或 regexp)是一種用來比對文本模式的工具,它可以用來搜尋、替換和驗證文本。正規表達式由一些特殊字元和普通字元組成,這些字元表示了一些模式。

下面是一些常見的正規表達式文法:

1)字元比對

  • 普通字元:表示自身,例如 "a" 表示字元 a。
  • 元字元(特殊字元):表示某種特殊含義,例如 "." 表示比對任意字元,"\d" 表示比對數字,"\w" 表示比對字母、數字、下劃線。

示例:

import re

# 比對 "abc" 字元串
pattern = "abc"
text = "abc"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 3), match='abc'>

# 比對任意字元
pattern = "."
text = "abc"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 1), match='a'>

# 比對數字
pattern = "\d"
text = "123"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 1), match='1'>

# 比對字母、數字、下劃線
pattern = "\w"
text = "abc_123"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 1), match='a'>           

2)字元集合

  • 方括号:表示比對方括号中任意一個字元,例如 "[abc]" 表示比對字元 a、b、c 中的任意一個。
  • 範圍符号:表示比對某個範圍内的字元,例如 "[a-z]" 表示比對小寫字母 a 到 z 中的任意一個。
  • 量詞:"", "+", "?": 表示重複次數,"" 表示重複0次或多次,"+" 表示重複1次或多次,"?" 表示重複0次或1次。
  • "{m,n}": 表示重複次數的範圍,例如 "{2,4}" 表示重複2到4次。

示例:

import re

# 比對方括号中任意一個字元
pattern = "[abc]"
text = "a"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 1), match='a'>

# 比對小寫字母 a 到 z 中的任意一個
pattern = "[a-z]"
text = "a"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 1), match='a'>

# 重複0次或多次
pattern = "a*"
text = "aaa"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 3), match='aaa'>

# 重複1次或多次
pattern = "a+"
text = "aaa"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 3), match='aaa'>

# 重複0次或1次
pattern = "a?"
text = "aaa"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 1), match='a'>

# 重複2到4次
pattern = "a{2,4}"
text = "aaaa"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 4), match='aaaa'>           

3)定位符

  • "^": 表示比對開頭。
  • "#34;: 表示比對結尾。
  • "\b": 表示比對單詞邊界。
import re

# 比對開頭
pattern = "^a"
text = "abc"
result = re.match(pattern, text)
print(result) # <re.Match object; span=(0, 1), match='a'>

# 比對結尾
pattern = "c#34;
text = "abc"
result = re.search(pattern, text)
print(result) # <re.Match object; span=(2, 3), match='c'>

# 比對單詞邊界
pattern = r"\bcat\b"
text = "cat sat on the mat"
result = re.search(pattern, text)
print(result) # <re.Match object; span=(0, 3), match='cat'>           

4)分組

  • "()", "(?:)": 表示分組,可以對一個子表達式進行分組。
  • "|": 表示或關系。

1、定義分組

使用圓括号 () 來定義分組,分組可以嵌套,每個分組都有一個唯一的編号,從左到右按照左括号的順序編号。

import re
pattern = r"(\d{3})-(\d{4})-(\d{4})"
result = re.search(pattern, "Tel: 010-1234-5678")
print(result.group(0))  # 010-1234-5678
print(result.group(1))  # 010
print(result.group(2))  # 1234
print(result.group(3))  # 5678           

2、引用分組

可以在正規表達式中使用 \n 引用第 n 個分組,其中 n 是分組的編号。

import re
pattern = r"(\w+) \1"
result = re.search(pattern, "hello hello world")
print(result.group(0))  # hello hello
print(result.group(1))  # hello           

3、命名分組

除了使用編号引用分組,還可以使用 (?Ppattern) 文法給分組命名。

import re
pattern = r"(?P<first>\w+) (?P<last>\w+)"
result = re.search(pattern, "John Smith")
print(result.group(0))  # John Smith
print(result.group("first"))  # John
print(result.group("last"))  # Smith           

以上僅是正規表達式文法的一部分,實際上正規表達式還包括很多進階的文法,比如反向引用、零寬度斷言等。上面講使用到了Python 的re模式,接下來細講這個子產品。

三、Python 的 re 子產品

Python标準庫中的re子產品是用于正規表達式操作的子產品,提供了正規表達式的編譯、比對、查找、替換等功能。下面是re子產品的一些常用方法:

1)re.match() 方法

re.match() 函數從字元串的起始位置開始比對正規表達式,如果比對成功,就傳回一個比對對象。如果比對不成功,就傳回 None。

re.match() 的文法格式如下:

re.match(pattern, string, flags=0)           

參數:

  • pattern 是正規表達式
  • string 是要比對的字元串
  • flags 是可選參數,用于指定比對模式。

正規表達式可以包含一些可選标志修飾符來控制比對的模式。修飾符被指定為一個可選的标志。多個标志可以通過按位 OR(|) 它們來指定。如 re.I | re.M 被設定成 I 和 M 标志:

修飾符 描述
re.I 使比對對大小寫不敏感
re.M 多行比對,影響 ^ 和 $
re.L 做本地化識别(locale-aware)比對
re.S 使 . 比對包括換行在内的所有字元
re.U 根據Unicode字元集解析字元。這個标志影響 \w, \W, \b, \B
re.X 該标志通過給予你更靈活的格式以便你将正規表達式寫得更易于了解。

下面是一個簡單的例子:

import re

pattern = r"hello"
string = "hello world"

match_obj = re.match(pattern, string)

if match_obj:
    print("比對成功")
else:
    print("比對失敗")           

在這個例子中,正規表達式 pattern 是 "hello",要比對的字元串是 "hello world"。由于正規表達式和字元串的開頭都是 "hello",是以比對成功。

re.match() 傳回的是一個比對對象。如果比對成功,可以使用比對對象的方法和屬性來擷取比對結果,如 group() 方法可以傳回比對的字元串,start() 和 end() 方法可以傳回比對的起始位置和結束位置,等等。如果比對不成功,調用這些方法和屬性會出現異常。

  • start() 傳回比對開始的位置
  • end() 傳回比對結束的位置
  • span() 傳回一個元組包含比對 (開始,結束) 的位置

下面是一個擷取比對結果的例子:

import re

pattern = r"hello"
string = "hello world"

match_obj = re.match(pattern, string)

if match_obj:
    print("比對成功")
    print(match_obj.group())     # hello
    print(match_obj.start())     # 0
    print(match_obj.end())       # 5
    print(match_obj.span())      # (0, 5)
else:
    print("比對失敗")           

2)re.search() 方法

re.search() 方法在字元串中搜尋正規表達式的第一個比對項,并傳回一個比對對象。如果沒有找到比對項,就傳回 None。

re.search() 的文法格式如下:

re.search(pattern, string, flags=0)           

其中,pattern 是正規表達式,string 是要比對的字元串,flags 是可選參數,用于指定比對模式。比對模式在上面有具體講解。

下面是一個簡單的例子:

import re

pattern = r"hello"
string = "world hello"

match_obj = re.search(pattern, string)

if match_obj:
    print("比對成功")
else:
    print("比對失敗")           

在這個例子中,正規表達式 pattern 是 "hello",要比對的字元串是 "world hello"。由于字元串中包含 "hello",是以比對成功。

3)re.match() 與 re.search() 的差別

Python re 子產品中的 re.match() 和 re.search() 方法都用于在字元串中查找比對的模式。但是它們之間有一些差別。
  • re.match() 方法從字元串的起始位置開始比對,如果起始位置不比對,則傳回 None。是以,re.match() 隻能比對到字元串的開頭。
  • re.search() 方法在字元串中查找比對的模式,可以比對到字元串中任意位置的模式。

另外,兩個方法傳回的比對對象也有一些差別:

  • re.match() 方法傳回第一個比對的對象,如果沒有比對到任何内容,則傳回 None。
  • re.search() 方法傳回第一個比對的對象,如果沒有比對到任何内容,則傳回 None。

如果要比對整個字元串,通常建議使用 re.match() 方法;如果要比對字元串中的一部分,或者不确定比對的位置,通常建議使用 re.search() 方法。

下面是一個例子,展示了兩個方法之間的差別:

import re

pattern = r"hello"
string = "world hello"

# 使用 re.match() 方法
match_obj = re.match(pattern, string)
if match_obj:
    print("re.match() 比對成功")
    print(match_obj.group())   # 輸出 "None"

# 使用 re.search() 方法
match_obj = re.search(pattern, string)
if match_obj:
    print("re.search() 比對成功")
    print(match_obj.group())   # 輸出 "hello"           

在這個例子中,正規表達式 pattern 是 "hello",要比對的字元串是 "world hello"。由于字元串的開頭不是 "hello",是以 re.match() 方法無法比對,傳回 None;而 re.search() 方法可以在字元串中找到 "hello",比對成功。

4)re.findall() 方法

re.findall() 方法用于在字元串中查找正規表達式比對的所有子串,并傳回一個清單。如果沒有比對項,傳回一個空清單。

re.findall() 方法的文法格式如下:

re.findall(pattern, string, flags=0)           

其中,pattern 是正規表達式,string 是要比對的字元串,flags 是可選參數,用于指定比對模式。比對模式在上面有具體講解。

下面是一個簡單的例子:

import re

pattern = r"\d+"
string = "2 apples, 5 bananas, 1 orange"

result = re.findall(pattern, string)

print(result)   # ['2', '5', '1']           

在這個例子中,正規表達式 pattern 是 "\d+",要比對的字元串是 "2 apples, 5 bananas, 1 orange"。"\d+" 表示比對一個或多個數字,是以傳回的結果是一個包含所有數字的清單。

【注意】re.findall() 方法傳回的是一個字元串清單,其中的每個字元串都是一個比對的子串。如果正規表達式包含分組,傳回的清單将包含所有分組比對的字元串。

5)re.finditer() 方法

re.finditer() 方法與 re.findall() 方法類似,都可以在字元串中使用正規表達式進行比對,但它傳回的不是一個清單,而是一個疊代器,可以通過疊代器逐個通路比對結果。

re.finditer() 方法的文法格式如下:

re.finditer(pattern, string, flags=0)           

其中,pattern 是正規表達式,string 是要比對的字元串,flags 是可選參數,用于指定比對模式。

下面是一個簡單的例子:

import re

pattern = r"\d+"
string = "2 apples, 5 bananas, 1 orange"

result = re.finditer(pattern, string)

for match in result:
    print(match.group())           

在這個例子中,正規表達式 pattern 是 "\d+",要比對的字元串是 "2 apples, 5 bananas, 1 orange"。使用 re.finditer() 方法進行比對,傳回的結果是一個疊代器,可以通過 for 循環逐個通路比對結果。每個比對結果都是一個 Match 對象,可以使用 match.group() 方法擷取比對的内容。

re.finditer() 方法與 re.findall() 方法的差別在于,re.findall() 方法傳回一個包含所有比對結果的清單,而 re.finditer() 方法傳回一個疊代器,可以逐個通路比對結果,這在處理大量資料時可以節省記憶體。

6)re.sub() 方法

re.sub() 方法用于在字元串中查找正規表達式比對的子串,并将其替換為指定的字元串。re.sub() 方法傳回替換後的字元串。

re.sub() 方法的文法格式如下:

re.sub(pattern, repl, string, count=0, flags=0)           

其中,pattern 是正規表達式,repl 是替換字元串,string 是要進行替換的字元串,count 是可選參數,用于指定最多替換的次數,flags 是可選參數,用于指定比對模式。

下面是一個簡單的例子:

import re

pattern = r"\s+"
string = "hello  world"

result = re.sub(pattern, "-", string)

print(result)   # 'hello-world'           

在這個例子中,正規表達式 pattern 是 "\s+",要比對的字元串是 "hello world","\s+" 表示比對一個或多個空格。repl 參數是 "-",表示将比對到的空格替換為 "-",結果傳回的是 "hello-world"。

【注意】re.sub() 方法并不會改變原始的字元串,而是傳回一個新的字元串。如果想要在原始字元串中進行替換,可以将結果指派給原始字元串變量。

7)re.compile() 方法

re.compile() 方法用于将正規表達式編譯為一個模式對象,該模式對象可以用于比對字元串。

re.compile() 方法的文法格式如下:

re.compile(pattern, flags=0)           

其中,pattern 是要編譯的正規表達式,flags 是可選參數,用于指定比對模式。

編譯後的模式對象可以調用 match()、search()、findall() 和 sub() 等方法進行比對和替換操作。使用 re.compile() 方法編譯正規表達式可以提高多次使用同一模式的效率。

下面是一個簡單的例子:

import re

pattern = r"\d+"
string = "2 apples, 5 bananas, 1 orange"

regex = re.compile(pattern)
result = regex.findall(string)

print(result)   # ['2', '5', '1']           

在這個例子中,正規表達式 pattern 是 "\d+",要比對的字元串是 "2 apples, 5 bananas, 1 orange"。使用 re.compile() 方法将正規表達式編譯為一個模式對象 regex,然後調用 regex.findall() 方法進行比對,傳回的結果是一個包含所有數字的清單。

【注意】如果要使用編譯後的正規表達式進行比對,必須調用相應的模式對象的方法。如果直接在 re 子產品中使用正規表達式,Python 會自動将其編譯為一個模式對象。

8)re.split() 方法

re.split() 方法用于在字元串中使用正規表達式進行分割,并傳回一個清單。

re.split() 方法的文法格式如下:

re.split(pattern, string, maxsplit=0, flags=0)           

其中,pattern 是正規表達式,string 是要分割的字元串,maxsplit 是可選參數,用于指定最大分割次數,flags 是可選參數,用于指定比對模式。

下面是一個簡單的例子:

import re

pattern = r"\s+"
string = "hello  world"

result = re.split(pattern, string)

print(result)   # ['hello', 'world']           

在這個例子中,正規表達式 pattern 是 "\s+",要分割的字元串是 "hello world","\s+" 表示比對一個或多個空格。re.split() 方法将字元串按照正規表達式進行分割,并傳回一個清單,清單中的每個元素都是分割後的子串。

【注意】re.split() 方法不會在分割後的字元串中保留分割符,如果想要保留分割符,可以使用分組文法,例如:
import re

pattern = r"(\s+)"
string = "hello  world"

result = re.split(pattern, string)

print(result)   # ['hello', '  ', 'world']           

在這個例子中,正規表達式 pattern 是 "(\s+)",使用圓括号将 "\s+" 包含起來,表示将空格作為分組進行比對,re.split() 方法會保留分組比對的内容。傳回的結果是一個清單,清單中的元素是分割後的子串和分組比對的内容。

Python 的正規表達式常用的文法和方法就先講解到這裡了,更關鍵還是需要多使用加深印象的。有任何疑問的小夥伴歡迎給我留言哦,後續會持續更新相關技術文章,也可關注我的公衆号【大資料與雲原生技術分享】進行深入技術交流~