正則表達式
目錄如下
正則表達式入門
簡言之,正則表達式(regular expression)描述了一種字符串匹配的模式(pattern),可以用來檢查一個串是否含有某種子串、將匹配的子串替換或者從某個串中取出符合某個條件的子串等。
入門正則表達式最快最有效的方式便是例子——比如說查找硬盤文件時,會使用?
和*
等通配符:
1.data(\w)?\.dat
將查找如下文件:
data.dat
data1.dat
data2.dat
datax.dat
dataN.dat
-
?
匹配0或1個字符 -
*
匹配0或多個字符
實例1
只允許英文字母、數字、下劃線、英文句號、以及中劃線組成
舉例:[email protected]
分析郵件名稱部分:
- 26個大小寫英文字母表示爲
a-zA-Z
- 數字表示爲
0-9
- 下劃線表示爲
_
- 中劃線表示爲
-
- 由於名稱是由若干個字母、數字、下劃線和中劃線組成,所以需要用到
+
表示多次出現
outlook郵箱正則如下:
[a-zA-Z0-9_-]+@outlook.com
爲什麼使用正則表達式?
典型的搜索和替換操作要求您提供與預期的搜索結果匹配的確切文本。雖然這種技術對於對靜態文本執行簡單搜索和替換任務可能已經足夠了,但它缺乏靈活性,若採用這種方法搜索動態文本,即使不是不可能,至少也會變得很困難。
通過使用正則表達式,可以:
-
測試字符串內的模式。
例如,可以測試輸入字符串,以查看字符串內是否出現電話號碼模式或信用卡號碼模式。這稱爲數據驗證。實例:
#re.search 掃描整個字符串並返回第一個成功的匹配。
#re.search(pattern, string, flags=0)
import re
phonePatt=re.compile(r'(13[0-9][0-9]{4}[0-9]{4})')
info='電話:13529384859'
print('電話:',phonePatt.search(info).group(1))
-
替換文本。
可以使用正則表達式來識別文檔中的特定文本,完全刪除該文本或者用其他文本替換它。實例1:
#re模塊提供了re.sub用於替換字符串中的匹配項。
#re.sub(pattern, repl, string, count=0, flags=0)
'''
repl : 替換的字符串,也可爲一個函數。
count : 模式匹配後替換的最大次數,默認 0 表示替換所有的匹配。
flags : 編譯時用的匹配模式,數字形式。
'''
import re
phone='電話:13529384859 #欠費了'
#刪除註釋
num=re.sub(r'#.*$','',phone)
print('phonenumber:',num)
#移除非數字內容
num=re.sub(r'\D','',phone)
print('phonenumber:',num)
例如,您可能需要搜索整個網站,刪除過時的材料,以及替換某些 HTML 格式標記。在這種情況下,可以使用正則表達式來確定在每個文件中是否出現該材料或該 HTML 格式標記。此過程將受影響的文件列表縮小到包含需要刪除或更改的材料的那些文件。然後可以使用正則表達式來刪除過時的材料。最後,可以使用正則表達式來搜索和替換標記。
命令或環境 | . | [] | ^ | $ | \(\) | \{\} | ? | + | | | () |
---|---|---|---|---|---|---|---|---|---|---|
python | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
組件——普通字符和元字符
正則表達式的組件可以是單個的字符、字符集合、字符範圍、字符間的選擇或者所有這些組件的任意組合。
普通字符
包括沒有顯式指定爲元字符的所有可打印和不可打印字符,即大寫和小寫字母、所有數字、所有標點符號和一些其他符號。
非打印字符
字符 | 描述 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須爲 A-Z 或 a-z 之一。否則,將 c 視爲一個原義的 ‘c’ 字符。 |
\f | 匹配一個換頁符。等價於 \x0c 和 \cL。 |
\n | 匹配一個換行符。等價於 \x0a 和 \cJ。 |
\r | 匹配一個回車符。等價於 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]。注意 Unicode 正則表達式會匹配全角空格符。 |
\S | 匹配任何非空白字符。等價於 [^ \f\n\r\t\v]。 |
\t | 匹配一個製表符。等價於 \x09 和 \cI。 |
\v | 匹配一個垂直製表符。等價於 \x0b 和 \cK。 |
特殊字符——元字符
許多元字符要求在試圖匹配它們時特別對待。若要匹配這些特殊字符,必須首先使字符"轉義",即,將反斜槓字符\ 放在它們前面。下表列出了正則表達式中的特殊字符:
元字符 | 描述 |
---|---|
$ | 匹配輸入字符串的結尾位置。如果設置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,請使用\$。 |
( ) | 標記一個子表達式的開始和結束位置。子表達式可以獲取供以後使用。要匹配這些字符,請使用\( 和\)。 |
* | 匹配前面的子表達式零次或多次。要匹配 * 字符,請使用\ *。——貪婪 |
+ | 匹配前面的子表達式一次或多次。要匹配 + 字符,請使用\ +。——貪婪 |
. | 匹配除換行符 \n 之外的任何單字符。要匹配 . ,請使用 \. 。 |
[] | 標記一箇中括號表達式的開始和結束。要匹配 [,請使用 \[。 |
? | 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 ?。 |
\ | 將下一個字符標記爲或特殊字符、或原義字符、或向後引用、或八進制轉義符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配換行符。序列 ‘\\’ 匹配 “\”,而 ‘\(’ 則匹配 “(”。 |
^ | 匹配輸入字符串的開始位置;除非在方括號表達式中使用,表示不接受該方括號表達式中的字符集合。要匹配 ^ 字符本身,請使用 \^。 |
{ | 標記限定符表達式的開始。要匹配 {,請使用 \{。 |
| | 指明兩項之間的一個選擇。要匹配 |,請使用 \ |
貪婪與非貪婪模式影響的是被量詞修飾的子表達式的匹配行爲,貪婪模式在整個表達式匹配成功的前提下,儘可能多的匹配,而非貪婪模式在整個表達式匹配成功的前提下,儘可能少的匹配。非貪婪模式只被部分NFA引擎所支持。
實例:
str='<h1>油菜花紫菜花</h1>'
#貪婪匹配
pattern_greed='<.*>' #會匹配整個字符串
#後面加上一個?就可以實現非貪婪或最小匹配
pattern_nongreed='<.*?>' #結果<h1>
限定符
限定符用來指定正則表達式的一個給定組件必須要出現多少次才能滿足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6種
限定符 | 描述 |
---|---|
* | 匹配前面的子表達式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等價於{0,}。 |
+ | 匹配前面的子表達式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等價於 {1,}。 |
? | 匹配前面的子表達式零次或一次。例如,“do(es)?” 可以匹配 “do” 、 “does” 中的 “does” 、 “doxy” 中的 “do” 。? 等價於 {0,1}。 |
{n} | n 是一個非負整數。匹配確定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的兩個 o。 |
{n,} | n 是一個非負整數。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等價於 ‘o+’。‘o{0,}’ 則等價於 ‘o*’。 |
{n,m} | m 和 n 均爲非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 將匹配 “fooooood” 中的前三個 o。‘o{0,1}’ 等價於 ‘o?’。請注意在逗號和兩個數之間不能有空格。 |
定位符
定位符使您能夠將正則表達式固定到行首或行尾。它們還使您能夠創建這樣的正則表達式,這些正則表達式出現在一個單詞內、在一個單詞的開頭或者一個單詞的結尾。
定位符 | 描述 |
---|---|
^ | 匹配輸入字符串開始的位置。如果設置了 RegExp 對象的 Multiline 屬性,^ 還會與 \n 或 \r 之後的位置匹配。 |
$ | 匹配輸入字符串結尾的位置。如果設置了 RegExp 對象的 Multiline 屬性,$ 還會與 \n 或 \r 之前的位置匹配。 |
\b | 匹配一個單詞邊界,即字與空格間的位置。 |
\B | 非單詞邊界匹配——任何其他位置 |
^
和$
都好理解,但什麼是\b,什麼是單詞邊界呢?
**注意:**不能將限定符與定位符一起使用。由於在緊靠換行或者單詞邊界的前面或後面不能有一個以上位置,因此不允許諸如 ^* 之類的表達式。
實例:
#匹配一個章節標題,該標題只包含兩個尾隨數字,並且出現在行首
p1='^Chapter [1-9][0-9]{0,1}'
#由於一般標題獨佔一行,避免匹配交叉引用
p2='^Chapter [1-9][0-9]{0,1}$'
#匹配單詞 Chapter 的開頭三個字符,因爲這三個字符出現在單詞邊界後面
p3='\bCha'
'''\b 字符的位置是非常重要的。如果它位於要匹配的字符串的開始,它在單詞的開始處查找匹配項。如果它位於字符串的結尾,它在單詞的結尾處查找匹配項'''
#匹配單詞 Chapter 中的字符串ter
p4='ter\b'
#匹配 Chapter 中的字符串 apt,但不匹配 aptitude 中的字符串 apt
p5='\Bapt' #對於 \B 非單詞邊界運算符,位置不重要,因爲不關心究竟是單詞的開頭還是結尾。
特殊字符類
特殊字符 | 描述 |
---|---|
. | 匹配除 “\n” 之外的任何單個字符。要匹配包括 ‘\n’ 在內的任何字符,請使用像 ‘[.\n]’ 的模式。 |
\d | 匹配一個數字字符。等價於 [0-9]。 |
\D | 匹配一個非數字字符。等價於 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價於 [^ \f\n\r\t\v]。 |
\w | 匹配包括下劃線的任何單詞字符。等價於’[A-Za-z0-9_]’。 |
\W | 匹配任何非單詞字符。等價於 ‘[^A-Za-z0-9_]’。 |
正向預查和反向預查
用圓括號將所有選擇項括起來,相鄰的選擇項之間用|分隔。但用圓括號會有一個副作用,使相關的匹配會被緩存,此時可用?:放在第一個選項前來消除這種副作用。
其中**?:**
是非捕獲元之一,還有兩個非捕獲元是**?=**
和**?!
**,這兩個還有更多的含義,前者爲正向預查,在任何開始匹配圓括號內的正則表達式模式的位置來匹配搜索字符串,後者爲負向預查,在任何開始不匹配該正則表達式模式的位置來匹配搜索字符串。
- (?:pattern) 非獲取匹配,匹配pattern但不獲取匹配結果,不進行存儲供以後使用。這在使用或字符“(|)”來組合一個模式的各個部分是很有用。例如“industr(?:y|ies)”就是一個比“industry|industries”更簡略的表達式。
- (?=pattern) 非獲取匹配,正向肯定預查(要匹配的文本先滿足此子模式前面的表達式——此處Windows),在任何匹配pattern的字符串開始處匹配查找字符串,該匹配不需要獲取供以後使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。預查不消耗字符,也就是說,在一個匹配發生後,在最後一次匹配之後立即開始下一次匹配的搜索,而不是從包含預查的字符之後開始。
- (?!pattern) 非獲取匹配,正向否定預查,在任何不匹配pattern的字符串開始處匹配查找字符串,該匹配不需要獲取供以後使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。
- (?<=pattern) 非獲取匹配,反向肯定預查(要匹配的文本先滿足此子模式後面的表達式——此處Windows),與正向肯定預查類似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。pattern中不能有+,*等不定長度的量詞
- (?<!pattern) 非獲取匹配,反向否定預查,與正向否定預查類似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。pattern中不能有+,*等不定長度的量詞
實例:
a. 檢測密碼強度
強密碼(必須包含大小寫字母和數字的組合,不能使用特殊字符,長度在 8-10 之間):
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
。使用了正向肯定預查,可以使用.*,且預查不消耗字符。
強密碼(必須包含大小寫字母和數字的組合,可以使用特殊字符,長度在 8-10 之間):
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
。使用了正向肯定預查,可以使用.*,且預查不消耗字符。
反向引用
對一個正則表達式模式或部分模式兩邊添加圓括號將導致相關匹配存儲到一個臨時緩衝區中,所捕獲的每個子匹配都按照在正則表達式模式中從左到右出現的順序存儲。緩衝區編號從 1 開始,最多可存儲 99 個捕獲的子表達式。每個緩衝區都可以使用 \n 訪問,其中 n 爲一個標識特定緩衝區的一位或兩位十進制數。
可以使用非捕獲元字符 ?:、?= 或 ?! 來重寫捕獲,忽略對相關匹配的保存。
反向引用的作用通常是用來查找或限定重複、查找或限定指定標識配對出現等等。
表達式在匹配時,表達式引擎會將小括號 “( )” 包含的表達式所匹配到的字符串記錄下來。在獲取匹配結果的時候,小括號包含的表達式所匹配到的字符串可以單獨獲取。
“\1” 引用第1對括號內匹配到的字符串,”\2” 引用第2對括號內匹配到的字符串……以此類推。
如果一對括號內包含另一對括號,則外層的括號先排序號。換句話說,哪一對的左括號 “(“ 在前,那這一對爲先。
實例:
供查找文本中兩個相同的相鄰單詞的匹配項的能力。
#查找重複4次以上不包括4次的單詞
import re
s1 = 'aaa bbbb ffffff 999999999'
patt1 =re.compile(r'(\w)(?=\1\1\1\1)(\1+)')
print(patt1.findall(s1))
[('b', 'bbb'), ('f', 'fffff'), ('9', '99999999')]
#findall()在字符串中找到正則表達式所匹配的所有子串,並返回一個列表,如果沒有找到匹配的,則返回空列表。
#\1 指定第一個子匹配項
實例2:
import os
def backrefer(regex,subject):
return re.findall(regex,subject)
#匹配出三連的字符串
fa=backrefer(r'(.+)\1\1','d123123123e')
#['123']
fa1=backrefer(r'((.+))\1\2','d123123123e')
#['123']
#匹配出html標籤內的文字
ht1=backrefer(r'.*<(.+)>(.*)<\/\1>.*','asdwas<td>ssd</td>sdasdd')
#[('td', 'ssd')] ——【(標籤,內容)】
實例3:
當一條字符串中含有2(組/個)連續的字符時,該字符串可以稱之爲“連續的字符串”。
例:2034384538452可以成爲“連續的字符串”,因爲其含有2次連續的3845。
請找出能夠判斷“連續的字符串”的方法,輸入可以用字符串或數組,輸入不能爲空,並且字符串長度必須大於等於1。
題主使用1與0來區分true和false,挑戰者也可以使用其他不同的值來區分true/false。
'''
abcab -> 0
bdefdefg -> 1
Hello, World! -> 1
pp.pp/pp -> 1
q -> 0
21020121012021020120210121020121012021012102012021020121012021020120210121020120210201210120210121020121012021020120210121020121012021012102012021020121012021012102012101202102012021012102012021020121012021020120210121020121012021012102012021020121012021020120210121020120210201210120210121020121012021020120210121020120210201210120210201202101210201210120210121020120210201210120210121020121012021020120210121020121012021012102012021020121012021020120210121020120210201210120210121020121012021020120 -> 0
'''
import backrefer
instance3=backrefer(r'(.+)\1',input())