字符 | 說明 |
---|---|
\ | 轉(zhuǎn)義符,表示轉(zhuǎn)義 |
. | 表示任意一個字符 |
+ | 表示重復(fù)1次或多次 |
* | 表示重復(fù)0次或多次 |
? | 表示重復(fù)0次或1次 |
| | 選擇符號,表示“或關(guān)系”,例如:A | B 表示匹配A或B |
{} | 定義量詞 |
[] | 定義字符類 |
() | 定義分組 |
^ | 可以表示取反,或匹配一行的開始 |
$ | 匹配一行的結(jié)束 |
上面表格中\(zhòng)w+ 是元字符,它由兩個基本元字符(\
和+
)和一個普通字符 w
構(gòu)成。另外,還有.
元字符,它由兩個基本元字符\
和,
構(gòu)成。
學(xué)習(xí)正則表達式某種意義上講就是在學(xué)習(xí)元字符的使用
,元字符是正則表達式的重點也是難點。下面會分門別類地介紹元字符的具體使用。
在正則表達式中有時也需要字符轉(zhuǎn)義,比如 w字符
不表示英文字母 w,而是表示任何語言的單詞字符(如英文字母、亞洲文字等)、數(shù)字和下畫線等內(nèi)容時,需要在w
字母前加上反斜杠\
。反斜杠\
也是基本元字符,與 Python
語言中的字符轉(zhuǎn)義是類似的。不僅可以對普通字符進行轉(zhuǎn)義,還可以對基本元字符進行轉(zhuǎn)義。如上面的表格,其中點.
字符是希望按照點.
的字面意義使用,作為.com
域名的一部分,而不是作為.
基本元字符使用,所以需要加反斜杠\
進行轉(zhuǎn)義,即\.
才是表示點.
的字面意義。
本節(jié)通過一個示例介紹在 Python中如何使用正則表達式。
在1.1.1 節(jié)介紹基本元字符時介紹了^
和$
,它們可以用于匹配一行字符串的開始和結(jié)束。當(dāng)以^
開始時,要求一行字符串的開始位置匹配:當(dāng)以$
結(jié)束時,要求一行字符串的結(jié)位置匹配。所以正則表達式\w+@jiakecong.com
和^w+@jiakecong.com$
是不同的。
示例代碼如下:
import re p1 = r'\w+@jiakecong\.com' p2 = r'^\w+@jiakecong\.com$' text = "Tony 's email is tony_guan111@jiakecong.com" m = re.search(p1, text) print(m) m = re.search(p2, text) print(m) email = "tony_guan111@jiakecong.com" m = re.search(p2, email) print(m)
輸出結(jié)果如下:
re.Match object; span=(17, 43), match='tony_guan111@jiakecong.com'>
None
re.Match object; span=(0, 26), match='tony_guan111@jiakecong.com'>
在正則表達式中可以使用字符類,一個字符類定義一組字符,其中的任一一個字符出現(xiàn)在輸入字符串中即匹配成功。注意每次匹配只能匹配字符類中的一個字符。
定義一個普通的字符類需要使用[
和]
元字符類。例如想在輸入字符串中匹配Java
或java
,可以使用正則表達式[Jj]ava
,示例代碼如下:
p = r'[Jj]ava' m = re.search(p, 'I like Java and Python') print(m) m = re.search(p, 'I like JAVA and Python') print(m) m = re.search(p, 'I like java and python') print(m)
輸出結(jié)果如下:
re.Match object; span=(7, 11), match='Java'>
None
re.Match object; span=(7, 11), match='java'>
上述代碼中除了JAVA
不匹配正則表達式[Jj]ava
,其他都匹配
在正則表達式中指定不想出現(xiàn)的字符,可以在字符類前加^
符號。示例代碼如下:
import re p = r'[^0123456789]' m = re.search(p, '1000') print(m) m = re.search(p, 'python') print(m)
上述代碼定義的正則表達式[^0123456789]
,它表示輸入字符串中出現(xiàn)非0-9數(shù)字即匹配,即出現(xiàn)在[0123456789]
以外的任意一字符即匹配
上面示例中的[^0123456789]
正則表達式,事實上有些麻煩,這種連續(xù)的數(shù)字可以使用區(qū)間表示。區(qū)間是用連字符-
表示的,例如[0123456789]
采用區(qū)間表示為[0-9]
,[^0123456789]
采用區(qū)間表示為[^0-9]
。區(qū)間還可以表示連續(xù)的英文字母字符類,例如[a-z]
表示所有小寫字母字符類,[A-Z]
表示所有大寫字母字符類。
另外,也可以表示多個不同區(qū)間,[A-Za-z0-9]
表示所有字母和數(shù)字字符類,[0-25-7]
表示0、1、2、5、6、7幾個字符組成的字符類。
示例代碼如下:
import re m = re.search('[A-Za-z0-9]', 'A10.3') print(m) m = re.search(r'[0-25-7]', 'A3489C') print(m)
輸出結(jié)果如下:
re.Match object; span=(0, 1), match='A'>
None
有些字符類很常用,例如[0-9]
等。為了書寫方便,正則表達式提供了預(yù)定義的字符類,例如預(yù)定義字符類\d
等價于[0-9]
字符類。預(yù)定義字符類如下圖所示
字符 | 說明 |
---|---|
. | 匹配任意一個字符 |
\ | 匹配反斜杠\字符 |
\n | 匹配換行 |
\r | 匹配回車 |
\f | 匹配一個換頁符 |
\t | 匹配一個水平制表符 |
\v | 匹配一個垂直制表符 |
\s | 匹配一個空格符,等價于[\t\n\r\f\v] |
\S | 匹配一個非空格符,等價于[^\s] |
\d | 匹配一個數(shù)字字符,等價于[0-9] |
\D | 匹配一個非數(shù)字字符,等價[^0-9] |
\w | 匹配任意語言的單詞字符、數(shù)字和下劃線'_'等字符,如果正則表達式標(biāo)志設(shè)置為ASCII,則只匹配[a-zA-Z0-9] |
\W | 等價于[^\w] |
示例代碼如下:
import re p = r'\D' m = re.search(p, 'assss') print(m) m = re.search(p, '1000') print(m) text = '你們好hello' m = re.search(r'\w', text) print(m)
輸出結(jié)果如下:
re.Match object; span=(0, 1), match='a'>
None
re.Match object; span=(0, 1), match='你'>
上述代碼正則表達式\D
就等于[^0123456789]
。另一個正則表達式\w
表示任意字符,會在text
字符串中查找匹配字符,找到的結(jié)果是你
字符。
之前學(xué)習(xí)的正則表達式元字符只能匹配顯示一次字符或字符串,如果想匹配顯示多次字符或字符串可以使用量詞
量詞表示字符或字符串重復(fù)的次數(shù),正則表達式中的量詞如下表:
字符 | 說明 |
---|---|
? | 出現(xiàn)0或1次 |
* | 出現(xiàn)0或多次 |
+ | 出現(xiàn)1或多次 |
{n} | 出現(xiàn)n次 |
{n,m} | 至少出現(xiàn)n次,但不超過m次 |
{n,} | 至少出現(xiàn)n次 |
量詞的使用示例代碼如下:
import re m = re.search(r'\d?', '87654321') print(m) m = re.search(r'\d?', 'ABC') print(m) m = re.search(r'\d*', '87654321') print(m) m = re.search(r'\d*', 'ABC') print(m) m = re.search(r'\d+', '87654321') print(m) m = re.search(r'\d+', 'ABC') print(m) m = re.search(r'\d{8}', '87654321') print(m) m = re.search(r'\d{8}', 'ABC') print(m) m = re.search(r'\d{7,8}', '87654321') print(m) m = re.search(r'\d{9, }', '87654321') print(m)
輸出結(jié)果如下:
re.Match object; span=(0, 1), match='8'>
re.Match object; span=(0, 0), match=''>
re.Match object; span=(0, 8), match='87654321'>
re.Match object; span=(0, 0), match=''>
re.Match object; span=(0, 8), match='87654321'>
None
re.Match object; span=(0, 8), match='87654321'>
None
re.Match object; span=(0, 8), match='87654321'>
None
量詞還可以細分為貪婪量詞和懶惰量詞,貪婪量詞會盡可能多地匹配字符,懶惰量詞會盡可能少地匹配字符。大多數(shù)計算機語言的正則表達式量詞默認是貪婪的,要想使用懶惰量詞在量詞后面加?
即可
示例代碼如下:
import re m = re.search(r'\d{5,8}', '87654321') print(m) m = re.search(r'\d{5,8}?', '87654321') print(m)
輸出結(jié)果如下:
re.Match object; span=(0, 8), match='87654321'>
re.Match object; span=(0, 5), match='87654'>
上述代碼使用了貪婪量詞{5,8}
,輸入字符串87654321
是長度8位的數(shù)字字符串,盡可能多地匹配字符結(jié)果是87654321
。代碼使用懶惰量詞{5,8}?
,輸入字符串87654321
是長度8位的數(shù)字字符串,盡可能少的匹配字符結(jié)果是87654
。
在此之前學(xué)習(xí)的量詞只能重復(fù)顯示一個字符,如果想讓一個字符串作為整體使用量詞,可將整個字符串放到一對小括號中,這就是分組(也稱子表達式)
對正則表達式進行分組不經(jīng)可以對一個字符串整體使用量詞,還可以在正則表達式中引用已經(jīng)存在的分組。示例代碼如下:
import re p = r'(121){2}' m = re.search(p, '121121abcabc') print(m) print(m.group()) # 返回匹配的字符串 print(m.group(1)) # 返回第一組內(nèi)容 p = r'(\d{3,4})-(\d{7,8})' m = re.search(p, '010-87654321') print(m) print(m.group()) # 返回匹配字符串 print(m.groups()) # 獲得所有組內(nèi)容
輸出結(jié)果如下:
re.Match object; span=(0, 6), match='121121'>
121121
121
re.Match object; span=(0, 12), match='010-87654321'>
010-87654321
('010', '87654321')
上述代碼定義的正則表達式(121)是將121字符串分為一組,(121){2}表示對121重復(fù)兩次,即121121。代碼調(diào)用match
對象的group()
方法返回匹配的字符串,group()
方法語法如下:
match.group([group1, ...])
其中參數(shù)group1
是組編號,在正則表達式中組編號是從1開始的,所以代碼正則表達式m.group(1)
表示返回第一組內(nèi)容
代碼 r'(\d{3,4})-(\d{7,8})'
正則表達式可以用來驗證固定電話號碼,在-
之前是3-4位的區(qū)號,-
之后是7-8位的電話號碼。在該正則表達式中有兩個分組。代碼m.groups()
方法是返回所有分組,返回值是一個元組
在Python程序中訪問分組時,除了可以通過組編號進行訪問,還可以通過組名進行訪問,前提是要在正則表達式中為組命名。組命名通過在組開頭添加?P分組名>
實現(xiàn)。
示例代碼如下:
import re p = r'(?Parea_code>\d{3,4})-(?Pphone_code>\d{7,8})' m = re.search(p, '010-87654321') print(m) print(m.group()) # 返回匹配字符串 print(m.groups()) # 獲得所有組內(nèi)容 # 通過組編號返回組內(nèi)容 print(m.group(1)) print(m.group(2)) # 通過組名返回組內(nèi)容 print(m.group('area_code')) print(m.group('phone_code'))
輸出結(jié)果如下:
re.Match object; span=(0, 12), match='010-87654321'>
010-87654321
('010', '87654321')
010
87654321
010
87654321
上述代碼其實和1.4.1的代碼是一樣的,只是給正則表達式命名了,以后就可以通過組編號或組名字來訪問
除了可以在程序diamante中訪問正則表達式匹配之后的分組內(nèi)容,還可以再正則表達式內(nèi)部引用之前的分組。
下面通過示例熟悉以下反向引用分組。假設(shè)由于工作需要想解析一段XML代碼,需要找到某一個開始標(biāo)簽和結(jié)束標(biāo)簽,示例代碼如下:
import re p = r'([\w]+)>.*/([\w]+)>' m = re.search(p, 'a>abc/a>') print(m) p = r'([\w]+)>.*/([\w]+)>' m = re.search(p, 'a>abc/b>') print(m)
輸出結(jié)果如下:
re.Match object; span=(0, 10), match='a>abc/a>'>
re.Match object; span=(0, 10), match='a>abc/b>'>
上述代碼的正則表達式分成了兩組,兩組內(nèi)容完全一樣。但是測試結(jié)果發(fā)現(xiàn)他們都是匹配的,但是a>abc/b>
明顯不是有效的XML代碼,因為開始標(biāo)簽和結(jié)束標(biāo)簽應(yīng)該是一致的??梢姶ar'([\w]+)>.*/([\w]+)>'
并不能保證開始標(biāo)簽和結(jié)束標(biāo)簽是一致的。為了解決此問題,可以引用反向引用,即讓第二組反向引用第一組。在正則表達式中反向引用語法是\組編號
,組編號是從1開始的。示例代碼如下:
import re p = r'([\w]+)>.*/\1>' # 使用了反向引用 ① m = re.search(p, 'a>abc/a>') print(m) # 匹配 m = re.search(p, 'a>abc/b>') print(m) # 不匹配
輸出結(jié)果如下:
re.Match object; span=(0, 10), match='a>abc/a>'>
None
上述代碼第①行時定義正則表達式,其中\1
是反向引用第一個組,從運行結(jié)果可見字符串a>abc/a>
是匹配的,而a>abc/b>
字符串不匹配
前面介紹的分組稱為捕獲分組。捕獲分組的匹配子表達式結(jié)果被暫時保存到內(nèi)存中,以備表達式或其他程序引用,這個過程稱為"捕獲",捕獲結(jié)果可以通過組編號或組名進行引用。但是有時并不想引用子表達式的匹配結(jié)果,不想捕獲匹配結(jié)果,只是將小括號作為一個整體進行匹配,此時可以使用非捕獲分組,在組開頭使用?
,可以實現(xiàn)非捕獲分組
示例代碼如下:
import re s = 'img1.jpg,img2.jpg,img3.bmp' # 捕獲分組 p = r'\w+(\.jpg)' mlist = re.findall(p, s) ① print(mlist) # 非捕獲分組 p = r'\w+(?:\.jpg)' mlist = re.findall(p, s) ② print(mlist)
輸出結(jié)果如下:
['.jpg', '.jpg']
['img1.jpg', 'img2.jpg']
上述代碼實現(xiàn)了從字符串中查找.jpg
結(jié)尾的文本,其中代碼第①行和第②行的正則表達式區(qū)別在于前者是捕獲分組,后者是非捕獲分組。捕獲分組將括號中的內(nèi)容作為子表達式進行捕獲匹配,將匹配的子表達式(即組的內(nèi)容)返回,結(jié)果是['.jpg','.jpg']
。而非捕獲分組將括號中的內(nèi)容作為普通的正則表達式字符串進行整體匹配,即找到.jpg
結(jié)尾的文本,所以最后結(jié)果是['img1.jpg', 'img2.jpg']
。
re
是Python
內(nèi)置的正則表達式模塊,前面雖然使用過re
模塊一些函數(shù),但還有很多重要函數(shù)沒有詳細介紹,這一節(jié)將詳細介紹這些函數(shù)
search()
和match()
函數(shù)非常相似,它們的區(qū)別如下所示
search()
:在輸入字符串中查找,返回第一個匹配內(nèi)容,如果找到一個則match
對象,如果沒有找到返回None
match()
:在輸入字符串開始處查找匹配內(nèi)容,如果找到一個則match
對象,如果沒有找到返回None
示例代碼如下:
import re p = r'\w+@jiakecong\.com' text = "Tony 's email is tony_guan111@jiakecong.com" ① m = re.search(p, text) print(m) m = re.match(p, text) print(m) email = 'tony_guan111@jiakecong.com' ② m = re.search(p, email) print(m) m = re.match(p, email) print(m) # match對象幾個方法 print('match對象幾個方法:') ③ print(m.group()) print(m.start()) print(m.end()) print(m.span())
輸出結(jié)果如下:
re.Match object; span=(17, 43), match='tony_guan111@jiakecong.com'>
None
re.Match object; span=(0, 26), match='tony_guan111@jiakecong.com'>
re.Match object; span=(0, 26), match='tony_guan111@jiakecong.com'>
match對象幾個方法:
tony_guan111@jiakecong.com
0
26
(0, 26)
上述代碼第①行輸入字符串開頭不是email
,search()
函數(shù)可以匹配成功,而match()
函數(shù)卻匹配失敗。代碼第②行輸入字符串開頭就是email格式的郵箱,所以search()
和match()
函數(shù)都可以匹配成功
search
和match()
函數(shù)如果匹配成功都返回match
對象。match
對象有一些常用方法,見代碼第③行。其中group()
方法返回匹配的子字符串;start()
方法返回子字符串的開始索引;end()
方法返回子字符串的結(jié)束索引;span
方法返回子字符串的跨度,它是一個二元素的元組。
findall()
和finditer()
函數(shù)非常相似,它們的區(qū)別如下所示
match
列表對象,如果匹配失敗則返回None
match
的可迭代對象,通過迭代對象每次可以返回一個match
對象,如果匹配失敗則返回None
示例代碼如下:
import re p = r'[Jj]ava' text = 'I like Java and java' match_list = re.findall(p, text) ① print(match_list) match_iter = re.finditer(p, text) ② for m in match_iter: ③ print(m.group())
輸出結(jié)果如下:
['Java', 'java']
Java
java
上述代碼第①行的findall()
函數(shù)返回match
列表對象。代碼第②行的finditer()
函數(shù)返回可迭代對象。代碼第③行通過for
循環(huán)遍歷可迭代對象
字符串分割使用split
函數(shù),該函數(shù)按照匹配的子字符串進行字符串分割,返回字符串列表對象
re.split(pattern, string, maxsplit=0, flags=0)
其中參數(shù)pattern
是正則表達式;參數(shù)string
是要分割的字符串;參數(shù)maxsplit
是最大分割次數(shù),maxsplit
默認值為零,表示分割次數(shù)沒有限制;參數(shù)flags
是編譯標(biāo)志
示例代碼如下:
import re p = r'\d+' text = 'AB12CD34EF' clist = re.split(p, text) ① print(clist) clist = re.split(p, text, maxsplit=1) ② print(clist) clist = re.split(p, text, maxsplit=2) ③ print(clist)
輸出結(jié)果如下:
['AB', 'CD', 'EF']
['AB', 'CD34EF']
['AB', 'CD', 'EF']
上述代碼調(diào)用split()
函數(shù)通過數(shù)字對AB12CD34EF
字符串進行分割,\d+
正則表達式匹配一到多個數(shù)字。
split()
函數(shù)中參數(shù)maxsplit
和flags
是默認的,分割的次數(shù)沒有限制,分割結(jié)果是['AB', 'CD', 'EF']
列表split()
函數(shù)指定maxsplit
為1,分割結(jié)果是['AB', 'CD34EF']
列表,列表元素的個數(shù)是maxsplit+1
。split()
函數(shù)指定maxsplit
為2,2是最大可能的分割次數(shù),因此maxsplit≥2
與maxsplit=0
是一樣的。字符串替換使用sub()
函數(shù),該函數(shù)用于替換匹配的子字符串,返回值是替換之后的字符串。
re.sub(pattern, rep1, string, count=0, flags=0)
其中參數(shù)pattern
是正則表達式;參數(shù)rep1
是替換字符串;參數(shù)string
是要提供的字符串;參數(shù)count
是要替換的最大數(shù)量,默認值為零,表示替換數(shù)量沒有限制;參數(shù)flags
是編譯標(biāo)志
示例代碼如下:
import re p = r'\d+' text = 'AB12CD34EF' replace_text = re.sub(p, ' ', text) ① print(replace_text) replace_text = re.sub(p, ' ', text, count=1) ② print(replace_text) replace_text = re.sub(p, ' ', text, count=2) ③ print(replace_text)
輸出結(jié)果如下:
AB CD EF
AB CD34EF
AB CD EF
上述代碼調(diào)用sub()
函數(shù)替換AB12CD34EF
字符串中的數(shù)字。
sub()
函數(shù)中參數(shù)count
和flags
都是默認的,替換的最大數(shù)量沒有限制,替換結(jié)果是AB CD EF
sub()
函數(shù)指定count
為1,替換結(jié)果是AB CD34EF
sub()
函數(shù)指定count
為2,2是最大可能的替換次數(shù),因此count≥2
與count=0
是一樣的。到此這篇關(guān)于超詳細講解python正則表達式的文章就介紹到這了,更多相關(guān)python正則表達式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
標(biāo)簽:三亞 烏魯木齊 安慶 銀川 湘西 呼倫貝爾 呼倫貝爾 葫蘆島
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《超詳細講解python正則表達式》,本文關(guān)鍵詞 超,詳細,講解,python,正則,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。