概念&作用
正則表達(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.IGNORECASE或re.I: 忽略大小寫匹配。 -
re.MULTILINE或re.M: 多行匹配,使^和$匹配字符串的每行的開頭和結(jié)尾,而不是整個(gè)字符串的開頭和結(jié)尾。 -
re.DOTALL或re.S: 讓.匹配任何字符,包括換行符。 -
re.UNICODE或re.U: 使\w,\W,\b,\B,\d,\D,\s,\S與Unicode字符集合匹配。 -
re.ASCII: 使\w,\W,\b,\B,\d,\D,\s,\S與ASCII字符集合匹配。 -
re.VERBOSE或re.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正則引擎更快地確定是否匹配。