一文搞定python正則表達(dá)式

概念&作用

正則表達(dá)式是一種用來描述文本模式的工具,它可以幫助你在字符串中查找匹配、替換符合某種模式的文本。通過使用正則表達(dá)式,你可以定義一些規(guī)則,然后在文本中查找符合這些規(guī)則的內(nèi)容。正則表達(dá)式可以用于各種編程語言和文本處理工具中,例如Python、JavaScript、Perl等。

python中的正則表達(dá)式

在python中,內(nèi)置的 re 模塊提供了對正則表達(dá)式的支持,這使得在 Python 中處理文本數(shù)據(jù)變得非常方便和高效。正則表達(dá)式在 Python 中非常有用,主要是因?yàn)閞e模塊具有強(qiáng)大的模式匹配功能、文本處理的靈活性、替換和修改文本的能力以及Python 的易用性和廣泛應(yīng)用。

基礎(chǔ)構(gòu)成

字符

正則表達(dá)式中的字符可以是字母、數(shù)字或符號,它們代表自身字符。例如,a 匹配字符 "a"。

元字符

元字符是具有特殊含義的字符,它們不僅僅代表自身字符。一些常見的元字符包括

元字符 作用含義
. 匹配除換行符以外的任意字符。
^ 匹配字符串的開頭。
$ 匹配字符串的結(jié)尾。
\d 匹配任意一個(gè)數(shù)字字符,相當(dāng)于 [0-9]
\D 匹配任意一個(gè)非數(shù)字字符,相當(dāng)于 [^0-9]
\w 匹配任意一個(gè)字母、數(shù)字或下劃線字符,相當(dāng)于 [a-zA-Z0-9_]
\W 匹配任意一個(gè)非字母、數(shù)字或下劃線字符,相當(dāng)于 [^a-zA-Z0-9_]
\s 匹配任意一個(gè)空白字符,包括空格、制表符、換行符等
\S 匹配任意一個(gè)非空白字符
\b 匹配單詞邊界,即字與空格之間的位置
\B 匹配非單詞邊界
* 匹配前一個(gè)字符的零個(gè)或多個(gè)。
+ 匹配前一個(gè)字符的一個(gè)或多個(gè)。
? 匹配前一個(gè)字符的零個(gè)或一個(gè)。
[] 匹配方括號內(nèi)的任意一個(gè)字符。例如,[aeiou]匹配任意一個(gè)元音字母。
| 匹配兩個(gè)或多個(gè)模式之一。
() 用于創(chuàng)建捕獲組,可以對匹配的內(nèi)容進(jìn)行分組。
量詞

量詞用于指定匹配字符重復(fù)出現(xiàn)的次數(shù),常見的量詞包括:

量詞 作用含義
{m} 精確匹配前一個(gè)字符出現(xiàn) m 次
{m,n} 匹配前一個(gè)字符出現(xiàn)至少 m 次,最多 n 次
{m,} 匹配前一個(gè)字符出現(xiàn)至少 m 次
* 匹配前一個(gè)字符的零個(gè)或多個(gè)
+ 匹配前一個(gè)字符的一個(gè)或多個(gè)
? 匹配前一個(gè)字符的零個(gè)或一個(gè)
原始字符串

在Python中,r字符串是一種特殊的字符串表示形式,被稱為原始字符串(raw string)。在原始字符串中,反斜杠 \ 不會(huì)被解釋為轉(zhuǎn)義字符,而是作為普通字符對待。這意味著在原始字符串中,反斜杠后面的字符會(huì)保持原樣,不會(huì)被轉(zhuǎn)義。

例如,在普通字符串中,要表示一個(gè)Windows文件路徑,你需要使用雙反斜杠來轉(zhuǎn)義,如下所示:

path = "C:\\Users\\username\\Documents\\file.txt"

而在原始字符串中,你可以直接寫成:

path = r"C:\Users\username\Documents\file.txt"

這使得處理一些特殊字符串,如正則表達(dá)式模式或文件路徑,更加方便,因?yàn)槟銦o需擔(dān)心轉(zhuǎn)義字符帶來的影響。

re模塊

Python 的正則表達(dá)式模塊 re 提供了一系列功能,讓你可以在字符串中進(jìn)行模式匹配、查找和替換等操作。你提到的 re.match()、re.search()、re.findall()re.sub()re.compile() 是其中常用的幾個(gè)函數(shù)。

re.match

re.match(pattern, string, flags=0)嘗試從字符串的開頭匹配一個(gè)模式。如果字符串開頭匹配成功,則返回一個(gè)匹配對象;否則返回 None。這意味著它只匹配字符串的開頭位置。

import re

pattern = r'hello'
string = 'hello world'
match_obj = re.match(pattern, string)
if match_obj:
    print("Match found:", match_obj.group())
else:
    print("No match found")

# Match found: hello
re.search

re.search(pattern, string, flags=0)re.match(pattern, string, flags=0)類似,但是它在整個(gè)字符串中搜索匹配項(xiàng),返回第一個(gè)匹配到的對象。這意味著它可以匹配字符串的任意位置。

import re

pattern = r'world'
string = 'hello world'
search_obj = re.search(pattern, string)
if search_obj:
    print("Match found:", search_obj.group())
else:
    print("No match found")

# Match found: world
re.findall

re.findall(pattern, string, flags=0)在字符串中找到所有匹配項(xiàng),并以列表的形式返回。它不同于 re.match()re.search(),它不返回匹配對象,而是直接返回匹配的字符串列表。

import re

pattern = r'lo'
string = 'hello world'
matches = re.findall(pattern, string)
print("Matches found:", matches)

# Matches found: ['lo']
re.sub

re.sub(pattern, repl, string, count=0, flags=0)用來在字符串中查找匹配項(xiàng),并替換為指定的字符串。它返回替換后的新字符串。

import re

pattern = r'world'
replacement = 'universe'
string = 'hello world'
new_string = re.sub(pattern, replacement, string)
print("New string:", new_string)

# New string: hello universe
re.compile

re.compile(pattern, flags=0)是Python 中用于預(yù)編譯正則表達(dá)式模式的函數(shù)。這個(gè)函數(shù)接受一個(gè)正則表達(dá)式作為參數(shù),并返回一個(gè)正則表達(dá)式對象,這個(gè)對象可以被用來執(zhí)行匹配操作。這個(gè)函數(shù)諸多優(yōu)點(diǎn):

  • 提高效率: 編譯后的正則表達(dá)式對象可以在多次使用時(shí)提高匹配效率。因?yàn)榫幾g后的對象已經(jīng)將正則表達(dá)式模式編譯為內(nèi)部數(shù)據(jù)結(jié)構(gòu),避免了每次匹配都要重新解析模式的開銷。
  • 可重用性: 編譯后的正則表達(dá)式對象可以在多個(gè)地方使用,而不需要每次都重新編譯正則表達(dá)式模式,提高了代碼的可重用性。
  • 簡化代碼: 將常用的正則表達(dá)式模式預(yù)先編譯,可以簡化代碼,使代碼更加清晰易懂。
import re

# 編譯正則表達(dá)式模式
pattern = re.compile(r'\d{3}-\d{3}-\d{4}')

# 使用編譯后的對象進(jìn)行匹配操作
result = pattern.search("John's phone number is 123-456-7890.")
if result:
   print("Phone number found:", result.group())
else:
   print("Phone number not found.")

# Phone number found: 123-456-7890
flag的可選值
  • re.IGNORECASEre.I: 忽略大小寫匹配。
  • re.MULTILINEre.M: 多行匹配,使 ^$ 匹配字符串的每行的開頭和結(jié)尾,而不是整個(gè)字符串的開頭和結(jié)尾。
  • re.DOTALLre.S: 讓 . 匹配任何字符,包括換行符。
  • re.UNICODEre.U: 使 \w, \W, \b, \B, \d, \D, \s, \SUnicode 字符集合匹配。
  • re.ASCII: 使 \w, \W, \b, \B, \d, \D, \s, \SASCII 字符集合匹配。
  • re.VERBOSEre.X: 忽略空白和注釋,使得更易讀的正則表達(dá)式能夠被編寫。

正/反向前瞻

正向前瞻(Positive Lookahead):正向前瞻用 (?=…) 表示,它指定了一個(gè)條件,在匹配位置的右側(cè)必須滿足這個(gè)條件才能匹配成功。但匹配的位置本身不會(huì)被包含在匹配結(jié)果中。

反向前瞻(Negative Lookahead):反向前瞻用 (?!…) 表示,它指定了一個(gè)條件,在匹配位置的右側(cè)必須不滿足這個(gè)條件才能匹配成功。同樣,匹配的位置本身不會(huì)被包含在匹配結(jié)果中。

接下來演示一下,假設(shè)我們要匹配一個(gè)字符串中的所有數(shù)字,但是要排除包含小數(shù)點(diǎn)的數(shù)字。我們可以使用正向前瞻來實(shí)現(xiàn)這個(gè)匹配:

import re

# 匹配所有不包含小數(shù)點(diǎn)的數(shù)字
pattern = r'\d+(?!\.)'
text = "123 456 7.89 10"

matches = re.findall(pattern, text)
print(matches)

# ['123', '456', '10']

在這個(gè)示例中,r'\d+(?!\.)' 匹配的是一串?dāng)?shù)字 \d+,但是它的右側(cè)不能跟著一個(gè)小數(shù)點(diǎn) (?!\.),這樣就排除了包含小數(shù)點(diǎn)的數(shù)字。

反向前瞻也可以用來排除某些特定情況的匹配。例如,假設(shè)我們要匹配所有不是以字母 "a" 開頭的單詞:

import re

# 匹配所有不以字母 "a" 開頭的單詞
pattern = r'\b(?!a)\w+\b'
text = "apple banana orange"

matches = re.findall(pattern, text)
print(matches)  
# ['banana', 'orange']

在這個(gè)示例中,r'\b(?!a)\w+\b' 匹配的是一個(gè)單詞,但是它的左側(cè)不能以字母 "a" 開頭 (?!a),這樣就排除了以 "a" 開頭的單詞 "apple"。

捕獲組和非捕獲組的概念

在正則表達(dá)式中,捕獲組和非捕獲組是用來對匹配的文本進(jìn)行分組和提取的工具, 比如Django/Flask等框架的url路由匹配就是用了這個(gè)。
捕獲組:捕獲組用括號 ( ) 表示,它可以將匹配的文本分組并保存到一個(gè)單獨(dú)的組中,以便后續(xù)引用或提取。捕獲組可以在整個(gè)正則表達(dá)式中通過反向引用(backreference)或在匹配結(jié)果中進(jìn)行訪問。

非捕獲組:非捕獲組也用括號 ( ) 表示,但是在左括號后緊跟著一個(gè)問號和冒號 (?: ),它用于對文本進(jìn)行分組,但不會(huì)在匹配結(jié)果中保存分組的內(nèi)容,也不會(huì)創(chuàng)建一個(gè)新的捕獲組。非捕獲組通常用于提高正則表達(dá)式的效率,因?yàn)樗粫?huì)占用額外的內(nèi)存來存儲(chǔ)匹配結(jié)果。

接下來演示一下, 假設(shè)我們有一個(gè)包含郵箱地址的字符串,我們想從中提取用戶名和域名部分。我們可以使用捕獲組來實(shí)現(xiàn):

import re

# 匹配郵箱地址的正則表達(dá)式
pattern = r'(\w+)@(\w+\.\w+)'

text = "jeff@xmishu.com, alice@baidu.com"

# 使用捕獲組提取用戶名和域名
matches = re.findall(pattern, text)
for match in matches:
    username, domain = match
    print("Username:", username)
    print("Domain:", domain)

在這個(gè)示例中,(\w+)(\w+\.\w+) 分別是兩個(gè)捕獲組,用來提取用戶名和域名。re.findall() 函數(shù)會(huì)返回一個(gè)列表,其中每個(gè)元素是一個(gè)包含用戶名和域名的元組。通過遍歷這個(gè)列表,我們可以輕松地獲取用戶名和域名部分。

實(shí)際應(yīng)用

正則表達(dá)式在python應(yīng)用中非常廣泛,它能輔助我們高效地處理很多問題

  • 數(shù)據(jù)提?。ňW(wǎng)頁數(shù)據(jù)采集等)
  • 文本處理(數(shù)據(jù)清洗、格式化入庫等)
  • web表單中用戶輸入內(nèi)容驗(yàn)證(郵箱密碼格式驗(yàn)證等)。

注意事項(xiàng)

  • 預(yù)編譯正則表達(dá)式:如果你要在多個(gè)地方使用相同的正則表達(dá)式,可以使用re.compile()預(yù)先編譯它,以提高匹配效率,生產(chǎn)環(huán)境中很有用。
  • 選擇最適合的函數(shù):Python的re模塊提供了多個(gè)函數(shù)用于正則表達(dá)式操作,如re.match()、re.search()、re.findall()等。根據(jù)需求選擇最適合的函數(shù),以避免不必要的性能開銷。
  • 使用非貪婪匹配:在量詞后面加上?可以將匹配模式變?yōu)榉秦澙纺J剑M可能少地匹配字符。例如,*?、+?、??
  • 避免過度使用 .:.可以匹配任意一個(gè)字符,但在某些情況下可能會(huì)導(dǎo)致性能下降。如果可能,盡量使用更具體的字符集或模式來限制匹配范圍。
  • 使用原始字符串:在編寫正則表達(dá)式時(shí),最好使用原始字符串(以r開頭),以避免不必要的轉(zhuǎn)義,提高代碼可讀性。
  • 使用字符類:字符類(如[0-9]、[a-zA-Z])比單個(gè)字符更有效率,因?yàn)樗鼈冊试S正則引擎更快地確定是否匹配。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容