簡介
-- 後面有很多習題,可以先做題目再來看文章
參考資料:https://docs.python.org/3/howto/index.html
正則表達式(Regular expressions REs或regexes或regex patterns)本質是小的且高度專業化的編程語言。它嵌入到 Python 中,調用使用re模塊。需要指定一些規則來描述那些你希望匹配的字符串集合。這些字符串集合可能包含英語句子、e-mail地址、TeX 命令,或任何你想要的東東。然後可以提出問題,例如“字符串是否匹配該模式?”或“模式是否匹配字符串?”。 您還可以使用RE修改字符串或以各種方式拆分它。
正則表達式模式被編譯成字節碼,然後由 C 語言寫的匹配引擎執行。對於高級的使用,你可能需要關注匹配引擎是如何執行給定RE,並通過一定的方式來編寫RE,以便產生運行得更快的字節碼。
正則表達式語言小而嚴格,不是所有的字符處理都可以使用正則表達式。還有一些任務,可以使用正則表達式來完成,但是表達式非常複雜。在這種情況下編寫 Python 代碼來處理會更好些;儘管 Python 代碼比精巧的正則表達式執行起來會慢一些,但可能會更容易理解。
簡單的模式
字符匹配
大多數字母和字符會匹配它們自身。舉個例子,正則表達式test將完全匹配字符串test(你可以啓用不區分大小寫模式,該正則表達式可以匹配Test或TEST)。
這條規則有例外; 有些字符是特殊的元字符,不匹配自身。 相反,它們匹配一些與衆不同的東西,或者通過重複它們或改變它們的含義來影響RE的其他部分。
這是元字符的完整列表
#!python
. ^ $ * + ? { } [ ] \ | ( )
方括號 [ ]指定用於存放你需要匹配的字符集合。例如 [abc] 會匹配字符 a,b 或 c;[a-c] 可以實現相同功能。後者使用範圍來表示與前者相同的字符集合。如果你想只匹配小寫字母,你的 RE 可能寫成 [a-z]。
注意方括號元字符在中不會觸發特殊功能例如 [akm'。
你還可以匹配方括號中未列出的所有其它字符,開頭添加 ^即可,例如 [^5] 會匹配除了 '5' 之外的任何字符。
元字符轉義:前面加上一個反斜槓,以消除它們的特殊功能:[,\ 。
反斜槓後邊跟一些字符還可以表示特殊的意義,例如表示十進制數字,表示所有的字母或者表示非空白的字符集合。
讓我們來舉個例子:\w 匹配任何單詞字符。如果正則表達式以字節的形式表示,這相當字符類 [a-zA-Z0-9_];如果正則表達式是一個字符串,\w 會匹配所有 Unicode 數據庫(unicodedata 模塊提供)中標記爲字母的字符。你可以在編譯正則表達式的時候,通過提供 re.ASCII 表示進一步限制 \w 的定義。
批註:re.ASCII 標誌使得 \w 只能匹配 ASCII 字符,不要忘了,Python3 是 Unicode 的。
下邊列舉一些反斜槓加字符構成的特殊含義:
特殊字符 | 含義 |
---|---|
\number | 匹配相同編號的組。組從1開始編號。例如,(.+) \1匹配'the the'或'55 55',但不匹配'thethe'(注意組後面的空格)。此特殊序列只能用於匹配前99個組。如果數字的第一個數字是0,或者數字是3個八進制數字長,則不會將其解釋爲組匹配,而是解釋爲具有八進制值編號的字符。在方括號內,所有數字轉義都被視爲字符。默認支持Unicode,中文標點也會作爲邊界。可以啓用re.ASCII。 |
\d | 匹配任何十進制數字,相當於類[0-9] |
\D | 與 \d 相反,匹配任何非十進制數字的字符,相當於 [^0-9] |
\s | 匹配任何空白字符(包含空格、換行符、製表符等),相當於類 [\t\n\r\f\v] |
\S | 與 \s 相反,匹配任何非空白字符,當相於類 [^\t\n\r\f\v] |
\w | 匹配任何字符,設置了re.ASCII的情況下等同於[a-zA-Z0-9_] |
\W | 與 \w 相反,設置了re.ASCII的情況下等同於[^a-zA-Z0-9_] |
\b | 匹配單詞的開始或結束 |
\B | 與 \b 相反 |
\A | 僅匹配字符串的開始。 |
\Z | 僅匹配字符串末尾。 |
例如 [\s,.] 匹配任何空白字符(/s 的特殊含義),',' 或 ‘.’ 。
轉義字符:
\a \b \f \n
\r \t \u \U
\v \x \\
'.'匹配除了換行符以外的任何字符。如果設置re.DOTALL,它將匹配包括換行在內的任何字符。
重複
'*' : 指定前一個字符匹配零次或者多次。
例如ca*t將匹配 ct(0 個 a),cat(1 個字符 a),caaat(3 個字符 a),等等。需要注意的是,由於受到 C 語言的 int 類型大小的內部限制,正則表達式引擎會限制字符 'a' 的重複個數不超過 20 億個;不過,通常我們工作也用不到那麼大的數據,你未必有這麼大的內存。
默認的是貪婪的,當你重複匹配一個 RE 時,匹配引擎會嘗試儘可能多的去匹配。直到RE不匹配或者到了結尾,匹配引擎就會回退一個字符,然後再繼續嘗試。
表達式 a[bcd]*b,首先需要匹配字符 'a',然後零個到多個 [bcd],最後以 'b' 結尾。那現在想象一下,這個 RE 匹配字符串 abcbd 會怎樣?
步驟 | 匹配 | 說明 |
---|---|---|
1 | a | 匹配 RE 的第一個字符 'a' |
2 | abcbd | 引擎在符合規則的情況下儘可能地匹配 [bcd]*,直到該字符串的結尾 |
3 | 失敗 引擎嘗試匹配 RE 最後一個字符 ‘b’,但當前位置已經是字符串的結尾,所以失敗告終 | |
4 | abcb | 回退,所以 [bcd]* 匹配少一個字符 |
5 | 失敗 | 再一次嘗試匹配 RE 最後一個字符 'b',但字符串最後一個字符是 'd',所以失敗告終 |
6 | abc | 再次回退,所以 [bcd]* 這次只匹配 'bc' |
7 | abcb | 再一次嘗試匹配這符 'b',這一次字符串當前位置指向的字符正好是 'b',匹配成功。最終,RE 匹配的結果是 abcb 。 |
另一個實現重複的元字符是 +,用於指定前一個字符匹配一次或者多次。
要特別注意 * 和 + 的區別:* 匹配的是零次或者多次,所以被重複的內容可能壓根兒不會出現;+ 至少需要出現一次。例如 ca+t 會匹配 cat 和 caaat,但不會匹配 ct 。
還有兩個表示重複的元字符,一個是問號?: 字符匹配零次或者一次。
元字符 {m,n}(m 和 n 都是十進制數),必須匹配 m 次到 n 次之間。例如 a/{1,3}b 會匹配 a/b,a//b 和 a///b 。但不會匹配 ab(沒有斜槓);也不會匹配 a////b(斜槓超過三個)。
你可以省略 m 或者 n,這樣的話,引擎會用合理的值代替。 m默認爲0;n 默認爲 20 億。
{0,}跟’*‘ 是一樣的;{1,}跟‘+’是一樣的;{0,1} 跟?是一樣的。不過還是鼓勵大家記住並使用 * 、+ 和 ?,因爲這些字符更短並且更容易閱讀。
習題
1, 下面那些不是python3正則表達式的元字符:
A $ B - C * D ? E /
參考答案:B E
2,python3正則表達式r'\bfoo\b'匹配下面哪些字符串
A 'foo' B 'foo.' C '(foo)' D 'bar foo baz' E 'foobar' F 'foo3'
參考答案:A B C D
3,python3正則表達式r'\bfoo\b'匹配下面哪些字符串
A 'foo,' B 'foo。' C '(foo!' D 'bar foo baz' E 'foobar' F 'foo3'
參考答案:A B C D
4,下面python3正則表達式元字符的描述哪些是錯誤的。
A. 默認\w不能匹配漢字
B. 默認\w能匹配漢字
C. 默認.能匹配換行符
D. 默認.不能匹配換行符
參考答案:A C
使用正則表達式
Python通過re模塊提供正則表達式支持,並可將正則表達式編譯成對象,用它們來進行匹配。
編譯正則表達式
正則表達式編譯爲模式對象,該對象擁有各種方法,如查找模式匹配或者執行字符串替換。
>>> import re
>>> p = re.compile('ab*')
>>> p
re.compile('ab*')
re.compile()也接受可選的flags 參數,用於開啓各種特殊功能和語法變化。
簡單的例子:
>>> p = re.compile('ab*', re.IGNORECASE)
正則表達式作爲字符串參數傳給 re.compile() 。由於正則表達式並不是 Python語言的核心部分,因此沒有爲它提供特殊的語法支持,所以正則表達式只能以字符串的形式表示。
原始字符串
'\section' 要用'\\section'表示。不巧,Python 字符串也使用 '\' 表示字符 ''。原始字符串則方便得多:r"\section"即可。
匹配
模式對象的常用方法:
方法 | 功能 |
---|---|
match() | 判斷正則表達式是否從開始處匹配一個字符串 |
search() | 遍歷字符串,找到正則表達式匹配的第一個位置 |
findall() | 遍歷字符串,找到正則表達式匹配的所有位置,並以列表的形式返回 |
finditer() | 遍歷字符串,找到正則表達式匹配的所有位置,並以迭代器的形式返回 |
如果沒有找到任何匹配的話,match() 和 search() 會返回 None;如果匹配成功,則會返回匹配對象(match object),包含所有匹配的信息:例如從哪兒開始,到哪兒結束,匹配的子字符串等等。
python自帶了正則表達式調試工具redemo.py:
實例:
>>> import re
>>> p = re.compile('[a-z]+')
>>> p
re.compile('[a-z]+')
>>> p.match("")
>>> print(p.match(""))
None
>>> m = p.match('tempo')
>>> m
<re.Match object; span=(0, 5), match='tempo'>
>>> m.group()
'tempo'
>>> m.start(), m.end()
(0, 5)
>>> m.span()
(0, 5)
匹配對象包含了很多方法和屬性,以下幾個是最重要的:
方法 | 功能 |
---|---|
group() | 返回匹配的字符串 |
start() | 返回匹配的開始位置 |
end() | 返回匹配的結束位置 |
span() | 返回元組表示匹配位置(start, end) |
match的start總是0,search() 方法則不一定了:
>>> print(p.match('::: message'))
None
>>> m = p.search('::: message'); print(m)
<re.Match object; span=(4, 11), match='message'>
>>> m.group()
'message'
>>> m.span()
(4, 11)
在實際應用中,最常用的方法是將匹配對象存放在局部變量中,並檢查其返回值是否爲 None 。
p = re.compile( ... )
m = p.match( 'string goes here' )
if m:
print('Match found: ', m.group())
else:
print('No match')
有兩個方法可以返回所有的匹配結果,一個是 findall(),一個是 finditer() 。
findall() 返回的是一個列表:
>>> p = re.compile(r'\d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
['12', '11', '10']
而 finditer() 則是將匹配對象作爲迭代器返回:
>>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')
>>> iterator
<callable_iterator object at 0x...>
>>> for match in iterator:
... print(match.span())
...
(0, 2)
(22, 24)
(29, 31)
模塊級函數
re 模塊同時還提供了一些全局函數,例如 match(),search(),findall(),sub() 等。這些函數跟模式對象同名方法一樣,只是增加了爲正則表達式字符串的第一個參數。
>>> print(re.match(r'From\s+', 'Fromage amk'))
None
>>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998')
<re.Match object; span=(0, 5), match='From '>
這些函數幫你自動創建模式對象,並調用相關的函數。它們還將編譯好的模式對象存放在緩存中,以便將來可以快速地直接調用。
在循環中大量的使用正則表達式,預編譯的話可以節省一些函數調用,用模式的方法更好。但如果是循環外部,因爲有內部緩存機制,兩者效率相差無幾。
編譯標識
編譯標識可修改正則表達式的工作方式。在 re 模塊下,編譯標識均有完整名和簡寫,例如 IGNORECASE 簡寫是 I。
標誌 | 含義 |
---|---|
ASCII,A | 使得轉義符號 \w,\b,\s 和 \d 只能匹配 ASCII 字符 |
DOTALL,S | 使得 . 匹配任何符號,包括換行符 |
IGNORECASE,I | 不區分大小寫 |
LOCALE,L | 支持當前語言(區域)設置 |
MULTILNE,M | 多行匹配,影響 ^ 和 $ |
VERBOSE,X(for'extended') | 啓用詳細的正則表達式, 更簡潔且更容易理解。 |
下面我們來詳細講解一下它們的含義:
- I
IGNORECASE
不區分大小寫。舉個例子,正則表達式[a-z] 或[A-Z]會匹配對應的小寫字母會匹配52個ASCII字母。還有4個非ASCII字母:'İ'(U + 0130,拉丁大寫字母I上面帶點),'ı'(U + 0131,拉丁文小寫字母無點i),'s'(U + 017F,拉丁文小 字母長s)和'K'(U + 212A,開爾文標誌)。 Spam 將匹配'Spam','spam','spAM'或'ſpam'(後者僅在Unicode模式下匹配)。 此小寫不考慮當前區域設置; 如果您還設置了LOCALE標誌,它也會。
- L
LOCALE
使得 \w,\W,\b 和 \B和大小寫依賴當前的語言(區域)環境,而不是 Unicode 數據庫。
區域設置是 C 語言的功能,主要作用是消除不同語言之間的差異。例如你正在處理的是法文文本,你想使用 \w+ 來匹配單詞,但是 \w 只是匹配 [A-Za-z] 中的單詞,並不會匹配那些法文特殊符號。python3已經推薦使用Unicode,不建議使用LOCALE。
- M
MULTILNE
通常 ^ 只匹配字符串的開頭,而 $ 匹配字符串的結尾。該標識設置時,^ 不僅匹配字符串的開頭,還匹配行首;$ 不僅匹配字符的結尾,還匹配行尾。
- S
DOTALL
. 可以匹配任何字符,包括換行符。如果不使用這個標誌,. 將匹配除換行的所有字符。
- A
ASCII
使得 \w,\W,\b,\B,\s 和 \S 只匹配 ASCII 字符,而不是全Unicode匹配。這個標識僅對Unicode模式有意義,並忽略字節模式。
- X
VERBOSE
這個標識使你的正則表達式可以寫得更可讀靈活,空格會被忽略(除了出現在字符類中和使用反斜槓轉義的空格);同時允許你在正則表達式字符串使用註釋,# 符號後邊的內容是註釋(除了出現在字符類中和使用反斜槓轉義的 #)。
下邊是使用 re.VERBOSE 的例子,:
charref = re.compile(r"""
&[#] # Start of a numeric entity reference
(
0[0-7]+ # Octal form
| [0-9]+ # Decimal form
| x[0-9a-fA-F]+ # Hexadecimal form
)
; # Trailing semicolon
""", re.VERBOSE)
# 沒有註釋
charref = re.compile("&#(0[0-7]+"
"|[0-9]+"
"|x[0-9a-fA-F]+);")
參考資料
- 討論qq羣144081101 591302926 567351477 釘釘免費羣21745728
- 本文最新版本地址
- 本文涉及的python測試開發庫 謝謝點贊!
- 本文相關海量書籍下載
- 本文源碼地址
習題
1,下面關於python3 正則模式的說哪些是錯誤的?
A. match() 可以返回多個匹配
B. search() 必須從開頭開始匹配
C. findall() 以迭代器的形式返回
D. finditer() 以列表的形式返回
答案:ABCD
2,python3 正則表達式re.compile('spam', re.IGNORECASE)匹配哪些字符串?
A.'Spam' B. 'spam' C. 'spAM' D. 'ſpam' E.'pam'
答案:ABCD
更多關於模式
更多元字符
- I
或操作符,對兩個正則表達式進行操作。如果 A 和 B 是正則表達式,A | B 會匹配 A 或 B 中出現的任何字符。爲了能夠更加合理的工作,| 的優先級非常低。例如 Crow|Servo匹配'Crow'或'Servo',,而不是匹配'Cro'、 'w' 、'S'、'ervo'.。
同樣,我們使用 | 來匹配 '|' 字符本身;或者包含在一個字符類中,像這樣 [|] 。
- ^
匹配字符串開始。在 MULTILNE 中,每當遇到換行符就會立刻進行匹配。如果你只希望匹配位於字符串開頭的單詞 From,那麼你的正則表達式可以寫爲 ^From
>>> print(re.search('^From', 'From Here to Eternity'))
<re.Match object; span=(0, 4), match='From'>
>>> print(re.search('^From', 'Reciting From Memory'))
None
- $
匹配字符串的結束和行尾。
>>> print(re.search('}$', '{block}'))
<re.Match object; span=(6, 7), match='}'>
>>> print(re.search('}$', '{block} '))
None
>>> print(re.search('}$', '{block}\n'))
<re.Match object; span=(6, 7), match='}'>
- A
匹配字符串開始,如果沒有設置 MULTILINE 標誌的時候,\A 和 ^ 的功能是一樣的;但如果設置了 MULTILNE 標誌, ^ 會對字符串的每一行都進行匹配。
- Z
匹配字符串的結束。
- b
單詞邊界,這是隻匹配單詞的開始和結尾的零寬斷言。單詞定義爲字母數字的序列,所以單詞的結束指的是空格或者非字母數字的字符。
>>> p = re.compile(r'\bclass\b')
>>> print(p.search('no class at all'))
<re.Match object; span=(3, 8), match='class'>
>>> print(p.search('the declassified algorithm'))
None
>>> print(p.search('one subclass is'))
None
在使用這些特殊的序列的時候,有兩點是需要注意的:第一是Python 的字符串跟正則表達式在有些字符上是有衝突的。比如說在 Python 中,\b 表示的是退格符,ASCII 碼值是 8。
下邊例子中,我們故意不寫表示原始字符串的 'r',結果確實大相庭徑:
>>> p = re.compile('\bclass\b')
>>> print(p.search('no class at all'))
None
>>> print(p.search('\b' + 'class' + '\b'))
<re.Match object; span=(0, 7), match='\x08class\x08'>
第二點是在字符類中不能使用這個斷言。在字符類中,\b 只是用來表示退格符。
- \B
與 \b 的含義相反,\B 表示非單詞邊界的位置。
分組
僅僅知道正則表達式是否匹配是不夠的,正則表達式通常使用分組的方式分別對不同內容進行匹配。
下例子將 RFC-822 頭用 “:” 號分成名字和值:
From: [email protected]
User-Agent: Thunderbird 1.5.0.9 (X11/20061227)
MIME-Version: 1.0
To: [email protected]
先用正則表達式匹配整個RFC-822頭,使用一個組來匹配頭的名字,另一個組匹配名字對應的值。
正則表達式使用元字符'(', ')' 來劃分組。'(', ')' 元字符跟數學表達式中的小括號含義差不多;它們將包含在內部的表達式組合在一起,所以你可以對組的內容使用重複操作的元字符,例如 *,+,? 或者 {m,n} 。
>>> p = re.compile('(ab)*')
>>> print(p.match('ababababab').span())
(0, 10)
用'(',')'表示的組也捕獲它們匹配的文本的起始和結束索引; 這可以通過將參數傳遞給ggroup(),start(),end() 和 span() 來檢索。 組從0開始編號。組0始終存在; 它是整個RE,因此匹配對象方法都將組0作爲其默認參數。
>>> p = re.compile('(a)b')
>>> m = p.match('ab')
>>> m.group()
'ab'
>>> m.group(0)
'ab'
子組從左到右進行編號,子組也允許嵌套,我們可以通過從左往右來統計左括號 ( 來確定子組的序號。
>>> p = re.compile('(a(b)c)d')
>>> m = p.match('abcd')
>>> m.group(0)
'abcd'
>>> m.group(1)
'abc'
>>> m.group(2)
'b'
group() 方法可傳入多個子組的序號:
>>> m.group(2,1,2)
('b', 'abc', 'b')
groups() 方法一次性返回所有的子組匹配的字符串:
>>> m.groups()
('abc', 'b')
反引用可以在後面的位置使用先前匹配過的內容,用法是反斜槓加上數字。例如 \1 表示引用前邊成功匹配的序號爲 1 的子組。
>>> p = re.compile(r'\b(\w+)\s+\1\b')
>>> p.search('Paris in the the spring').group()
'the the'
習題
1, python3正則表達式compile('Crow|Servo')匹配哪些內容:
A 'Crow' B 'foo。' C Servw' D 'Cro' E 'Serv' F 'Servo'
參考答案:A F
2, python3正則表達式要匹配'|',可以採用如下哪些方法:
A '||' B '|' C '[|]' D '$|'
參考答案:B C
3,關於python3正則表達式,下面哪些說法是正確的
A re.findall(r'^From', 'From Here to Eternity\nFrom', re.MULTILINE) 返回長度爲2的列表
B re.findall(r'^From', 'From Here to Eternity\nFrom') 返回長度爲2的列表
C re.findall(r'^From', ' From Here to Eternity\nFrom', re.MULTILINE) 返回長度爲2的列表
D re.findall(r'\bFrom', ' From Here to Eternity\nFrom', re.MULTILINE) 返回長度爲2的列表
參考答案:A D
4,關於python3正則表達式,下面哪些說法是正確的
A re.search(r'\bclass\b', 'no class at all')能成功匹配
B re.search('\bclass\b', 'no class at all')能成功匹配
C re.search(r'\bclass\b', 'no class at all')不能能成功匹配
D re.search('\bclass\b', 'no class at all')不能成功匹配
參考答案:A D
待整理: notepad++ 正則 http://docs.notepad-plus-plus.org/index.php/Regular_Expressions