文章目錄
一、什麼是正則表達式
通俗理解:
按照一定的規則,從某個字符串中匹配出想要的數據。這個規則就是正則表 達式。
官方參考:正則表達式
二、re模塊介紹
re模塊是python獨有的匹配字符串的模塊,該模塊中提供的很多功能是基於正則表達式實現的,而正則表達式是對字符串進行模糊匹配,提取自己需要的字符串部分,他對所有的語言都通用。注意:
- re模塊是python獨有的
- 正則表達式本質上是對字符串操作的邏輯公式,適用於所有程序語言。
- re模塊使python擁有全部的正則表達式功能
本章節主要介紹Python中常用的正則表達式處理函數。
三、常用正則表(元字符)
模式 | 描述 |
---|---|
\w | 匹配字母數字及下劃線 |
\W | 匹配 非 字母數字即下劃線 |
\s | 匹配任意 非 空白字符,等價於 [\t\n\r\f] |
\S | 匹配任意非空字符 |
\d | 匹配任意數字,等價於 [0-9] |
\D | 匹配任意非數字 |
\A | 匹配字符串開始 |
\z | 匹配字符串結束 |
\Z | 匹配字符串結束,如果存在換行,只匹配到換行前的結束字符串 |
\G | 匹配最後匹配完成的位置 |
\n | 匹配一個換行符 |
\t | 匹配一個製表符 |
^ | 匹配字符串開頭 |
$ | 匹配字符串末尾 |
. | 匹配任意字符,除了換行符,如果當re.DOTALL標記被指定時,則可以匹配包括換行符在內的任意字符 |
[…] | 用來表示一組字符,單獨列出:[abc] ,匹配"a",“b"或"c” |
[^…] | 不在[]中的字符:[ ^abc ] 匹配除了,a,b,c之外的字符 |
* | 匹配0個或者多個的表達式 |
+ | 匹配一個或者多個的表達式 |
? | 匹配0個或者1個由前面的正則表達式定義的片段,非貪婪匹配 |
{n} | 進準匹配n個前面的表達式 |
{n,m} | 匹配n到m次由前面的正則表達式定義的片段,也叫貪婪方式 |
a|b | 匹配a或者b |
{} | 匹配括號內的表達式,也表示一個組 |
3.1 \A,\z和^,$的區別
^: 指定匹配必須出現在字符串的開頭或行的開頭。
\A :指定匹配必須出現在字符串的開頭(忽略 Multiline 選項)。
$: 指定匹配必須出現在以下位置:字符串結尾、字符串結尾的 \n 之前或行的結尾。
\Z: 指定匹配必須出現在字符串的結尾或字符串結尾的 \n 之前(忽略 Multiline 選項)。
更多參考: 正則教程
四、re模塊用法示例
'''
re模塊基礎
Version:01
author:jasn
data:2020-04-16
'''
import re
# ==========================================================================================================================================
# 效果演示
str1 = 'In 2020, I must learn Python! & @'
# \w:匹配數字字母及下劃線
print(re.findall('\w',str1))
# 結果:['I', 'n', '2', '0', '2', '0', 'I', 'm', 'u', 's', 't', 'l', 'e', 'a', 'r', 'n', 'P', 'y', 't', 'h', 'o', 'n']
# \W:匹配非字母數字及下劃線
print(re.findall('\W', str1))
# 結果 :[' ', ',', ' ', ' ', ' ', ' ', '!', ' ', '&', ' ', '@']
# \s匹配任意空白符
print(re.findall('\s',str1))
# 結果:[' ', ' ', ' ', ' ', ' ', ' ', ' ']
# \S 匹配任意非空字符
print(re.findall('\S', str1))
# 結果:['I', 'n', '2', '0', '2', '0', ',', 'I', 'm', 'u', 's', 't', 'l', 'e', 'a', 'r', 'n', 'P', 'y', 't', 'h', 'o', 'n', '!', '&', '@']
# \d 匹配任意數字,等價於[0-9]
print(re.findall('\d', str1))
print(re.findall('[0-9]', str1)) # 結果相同
# 結果:['2', '0', '2', '0']
# 、\D 匹配任意非數字
print(re.findall('\D', str1))
# 結果 :['I', 'n', ' ', ',', ' ', 'I', ' ', 'm', 'u', 's', 't', ' ', 'l', 'e', 'a', 'r', 'n', ' ', 'P', 'y', 't', 'h', 'o', 'n', '!', ' ', '&', ' ', '@']
# A 匹配字符串的開始 ;\Z匹配字符串的結束,有返回匹配的值,無返回空
print(re.findall('\AIn', str1)) # ['In'],\A ==> ^
print(re.findall('@\Z', str1)) # ['@'],\Z ==> $
# ^ 匹配字符串的開頭;$匹配字符串的結束
print(re.findall('^I', str1)) # ['I']
print(re.findall('@$', str1)) # ['@']
'''
\A,\Z 和 $ ^ 的區別:
^: 指定匹配必須出現在字符串的開頭或行的開頭。
\A :指定匹配必須出現在字符串的開頭(忽略 Multiline 選項)。
$: 指定匹配必須出現在以下位置:字符串結尾、字符串結尾的 \n 之前或行的結尾。
\Z: 指定匹配必須出現在字符串的結尾或字符串結尾的 \n 之前(忽略 Multiline 選項)。
'''
# ===========================================================================================================================================
# 重複匹配:| . | * | ? | .* | .*? | + | {n,m} |
# ===========================================================================================================================================
# . 匹配任意字符,除換行符外
print(re.findall('a.b','a1b')) # ['a1b']
print(re.findall('a.b','a1b a*b a b aaab')) # ['a1b', 'a*b', 'a b', 'aab']
print(re.findall('a.b','a\nb')) # []
print(re.findall('a.b','a\nb', re.S)) # ['a\nb']
# 如果不使用re.S參數,則只在每一行內進行匹配,如果一行沒有,就換下一行重新開始。
# 而使用re.S參數以後,正則表達式會將這個字符串作爲一個整體,在整體中進行匹配。
print(re.findall('a.b','a\nb',re.DOTALL)) # ['a\nb']同上一條意思一樣
# re.DOTALL。這使得正則表達式中的句點(.)可以匹配所有的字符,也包括換行符
# * 匹配*左側字符 一個或者 多個
print(re.findall('ab*','bbbbbbb')) # []
print(re.findall('ab*','a')) # ['a']
print(re.findall('ab*','abbbb')) # ['abbbb']
# ? 匹配前面的子表達式 0 次或 1 次(等價於{0,1})
print(re.findall('ab?','a')) # ['a']
print(re.findall('ab?','abbb')) # ['ab']
# 匹配所有包含小數在內的數字
print(re.findall('\d+[.]?\d*',"asdfasdf123as1.13dfa12adsf1asdf3")) # ['123', '1.13', '12', '1', '3']
# .* 默認爲貪婪匹配,一直匹配到結尾最後一個值
print(re.findall('a.*b','a1b22222222b')) # 'a1b22222222b']
# .*? (固定格式) 爲非貪婪匹配:推薦使用,匹配到字符串第一個值
print(re.findall('a.*?b', 'a1b22222222b')) #['a1b']
# + 匹配前面的子表達式 1 次或多次(等價於{1, })
print(re.findall('ab','a')) # []
print(re.findall('ab+','abbb')) # ['abbb']
# {n,m} m 和 n 均爲非負整數,其中 n <= m,最少匹配 n 次且最多匹配 m 次
print(re.findall('ab{2}','abbb')) # ['abb'] 匹配2個b
print(re.findall('ab{2,4}','abbbbbb')) # ['abbbb'] 最少匹配2個,最多匹配4個
print(re.findall('ab{1,}','abbb')) # 'ab{1,}' ===> 'ab+' 匹配1個到無窮個
print(re.findall('ab{0,}','abbb')) # 'ab{0,}' ===> 'ab*' 匹配0個到無窮個
# ==============================================================================================================================================
# [] 用來表示一組字符,單獨列出
print(re.findall('a[1*-]b', 'a1b a*b a-b')) # []內的都爲普通字符了,且如果-沒有被轉意的話,應該放到[]的開頭或結尾
print(re.findall('a[^1*-]b', 'a1b a*b a-b a=b')) # []內的^代表的意思是取反,所以結果爲['a=b']
print(re.findall('a[0-9]b', 'a1b a*b a-b a=b')) # []內代表匹配任意0-9之間的值
print(re.findall('a[a-z]b', 'a1b a*b a-b a=b aeb')) # []內代表匹配任意a-z之間的值
print(re.findall('a[a-zA-Z]b', 'a1b a*b a-b a=b aeb aEb')) # []內代表匹配任意a-z和A-Z之間的值
# \
# print(re.findall('a\\c','a\c')) #對於正則來說a\\c確實可以匹配到a\c,但是在python解釋器讀取a\\c時,會發生轉義,然後交給re去執行,所以拋出異常
print(re.findall(r'a\\c','a\c')) #r代表告訴解釋器使用rawstring,即原生字符串,把我們正則內的所有符號都當普通字符處理,不要轉義
print(re.findall('a\\\c','a\c')) #同上面的意思一樣,和上面的結果一樣都是['a\\c']
# ===============================================================================================================================================
#():分組 匹配括號內表達式,也是一個分組
print(re.findall('ab+','ababab123')) # ['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123')) # ['ab'],匹配到末尾的ab123中的ab
print(re.findall('(?:ab)+123','ababab123')) # findall的結果不是匹配的全部內容,而是組內的內容, ?: (固定寫法) 可以讓結果爲匹配的全部內容
print(re.findall('href="(.*?)"','<a href="http://www.baidu.com">點擊</a>'))#['http://www.baidu.com']
print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com">點擊</a>'))#['href="http://www.baidu.com"']
'''
要理解?=和?!,?:,首先需要理解前瞻,後顧,負前瞻,負後顧四個概念:
// 前瞻:
exp1(?=exp2) 查找exp2前面的exp1
// 後顧:
(?<=exp2)exp1 查找exp2後面的exp1
// 負前瞻:
exp1(?!exp2) 查找後面不是exp2的exp1
// 負後顧:
(?<!exp2)exp1 查找前面不是exp2的exp1
(?:exp2) 匹配字符串中所有的exp2
'''
# |
print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
4.1 轉義字符
在正則表達式中,有很多有特殊意義的是元字符,比如\n和\s等,如果要在正則中匹配正常的"\n"而不是"換行符"就需要對""進行轉義,變成’\’。
正則 | 待匹配字符 | 匹配 結果 | 說明 | |
---|---|---|---|---|
\n | \n | False | 因爲在正則表達式中\是有特殊意義的字符,所以要匹配\n本身,用表達式\n無法匹配 | |
“\\n” | ‘\n’ | True | 在python中,字符串中的’‘也需要轉義,所以每一個字符串’'又需要轉義一次,轉義\之後變成\,即可匹配 | |
r’\n’ | r’\n’ | True | 在字符串之前加r,讓整個字符串不轉義 |
4.2 貪婪匹配和非貪婪匹配
貪婪匹配:在滿足匹配時,匹配儘可能長的字符串,默認情況下,採用貪婪匹配。
加上?爲將貪婪匹配模式轉爲非貪婪匹配模式,會匹配儘量短的字符串
# .* 默認爲貪婪匹配,一直匹配到結尾最後一個值
print(re.findall('a.*b','a1b22222222b')) # 'a1b22222222b']
# .*? (固定格式) 爲非貪婪匹配:推薦使用,匹配到字符串第一個值
print(re.findall('a.*?b', 'a1b22222222b')) #['a1b']
.*?的用法
. 是任意字符
* 是取 0 至 無限長度
? 是非貪婪模式。
何在一起就是 取儘量少的任意字符,一般不會這麼單獨寫,他大多用在:
.*?x
就是取前面任意長度的字符,直到一個x出現
4.3 字符集[]和分組()的區別
正則 | 用途 | 待匹配字符串 | 匹配正則 |
---|---|---|---|
[] | 用來表示一組字符,單獨列出 | 110101198001017032(身份證號碼) | ^ \d{13,16}[0-9x]$ |
() | 匹配括號內表達式 | href=“http://www.baidu.com” (獲取到網址) | href="(.*?)" |
五、re模塊的使用
5.1 賦值變量重用
import re
str1 = 'In 2020, I must learn Python!'
pattern = re.compile('\d+') # 如要反覆重用,可以使用這種方法,將模式編譯存在一個變量pattern中,便於重用
pattern.findall(str1) # ['2020']
5.2 直接使用
import re
str1 = 'In 2020, I must learn Python! & @'
re.findall('\d+',str1) #臨時使用,可以直接使用re下的方法:(模式,內容)
# ['2020']
六、re模塊常用函數
6.1 常用函數功能簡介
函數名 | 描述 |
---|---|
re.compile(pattern,flags = 0 ) | 將正則表達式模式編譯成正則表達式對象 |
findall(pattern,string,flags = 0 ) | 以string列表形式返回string中pattern的所有非重疊匹配項。從左到右掃描該字符串,並以找到的順序返回匹配項。如果該模式中存在一個或多個組,則返回一個組列表;否則,返回一個列表。如果模式包含多個組,則這將是一個元組列表。空匹配項包含在結果中。 |
re.match(pattern,string,flags = 0 ) | 從一個字符串的開始位置起匹配正則表達式,返回 match 對象,可以用search+^代替match |
re.search(pattern,string,flags = 0 ) | 會在字符串內查找模式匹配,直到找到第一個匹配然後返回 match 對象,如果字符串沒有匹配,則返回None |
re.finditer(pattern, string, flags=0) | 返回的是一個迭代器,每個迭代元素是 match 對象。 |
re.sub(pattern,repl,string,count = 0,flags = 0 ) | 用於替換字符串中的匹配項,返回通過用替換repl替換字符串中最左邊的不重疊模式所獲得的字符串。如果找不到該模式, 則返回的字符串不變。repl可以是字符串或函數;如果是字符串,則處理其中的任何反斜槓轉義。即,將其轉換爲單個換行符,將其轉換爲回車,依此類推。count參數表示將匹配到的內容進行替換的次數。 |
re.split(pattern,string,maxsplit = 0,flags = 0 ) | 通過出現模式來拆分字符串。如果在pattern中使用了捕獲括號,那麼模式中所有組的文本也將作爲結果列表的一部分返回。如果maxsplit不爲零,則最多會發生maxsplit分割,並將字符串的其餘部分作爲列表的最後一個元素返回。 |
re.escape(pattern) | 可以對文本(字符串)中所有可能被解釋爲正則運算符的字符進行轉義的應用函數。 |
6.2 re.Match對象下的方法和屬性
re.Match對象的方法
方法 | 描述 |
---|---|
.group() | 返回匹配項的一個或多個子組。如果有單個參數,則結果爲單個字符串;如果有多個參數,則結果是一個元組,每個參數有一個項目。沒有參數,group1默認爲零(返回整個匹配項)。如果groupN參數爲零,則對應的返回值是整個匹配字符串;否則,返回值爲0。 |
.start() | 匹配字符串在原始字符串的開始位置 |
.end() | 匹配字符串在原始字符串的結束位置 |
.span() | 返回(.start(), .end()) |
.groups() | 返回一個包含匹配項所有子組的元組,如果沒有則返回None |
re.Match對象的屬性
屬性 | 描述 |
---|---|
.string | 待匹配的文本 |
.re | 匹配時使用的 pattern 對象(正則表達式) |
.pos | 正則表達式搜索文本的開始位置 |
.endpos | 正則表達式搜索文本的結束位置 |
代碼實例
import re
text = "apple price is $99,orange price is $88"
result = re.search('.+(\$\d+).+(\$\d+)',text)
print(result)
# groups()的 用法
# ===================================================
print(result.groups())
# group()的 用法
# ===================================================
print(result.group()) # 整個匹配
print(result.group(1)) # 第一個括號內的子組
print(result.group(2)) # 第二個括號內的子組
print(result.group(1, 2)) # 以元組形式返回多個參數
6.3 常用函數代碼實例
import re
# 一:findall的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
# \w:匹配數字[0-9]
print(re.findall('\d',str1)) # 結果:['2', '0', '2', '0']
# 二:re.match的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
print(re.match('a', str1)) # 如果字符串開頭匹配不到,則返回None
print(re.match('In', str1)) # <re.Match object; span=(0, 2), match='In'>
# 用search+^ 實現match的功能
print(re.search('^In', str1)) # <re.Match object; span=(0, 2), match='In'>
# 三:re.search的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
print(re.search('In', str1)) # <re.Match object; span=(0, 2), match='In'>
print(re.search('e', str1).group()) # e,只到找到第一個匹配然後返回一個包含匹配信息的對象,該對象可以通過調用group()方法得到匹配的字符串,如果字符串沒有匹配,則返回None
# 四:re.finditer的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
s = re.finditer('\d', str1)
print(type(s)) # <class 'callable_iterator'> ,可調用的迭代器
for i in s:
print(i, end='\n')
'''
<re.Match object; span=(3, 4), match='2'>
<re.Match object; span=(4, 5), match='0'>
<re.Match object; span=(5, 6), match='2'>
<re.Match object; span=(6, 7), match='0'>
'''
# 五:re.sub的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
print(re.sub('C語言', 'java', str1)) # 如果找不到,則返回字符串不變 In 2020, I must learn Python! & @
print(re.sub('Python', 'java', str1)) # In 2020, I must learn java! & @
print(re.sub('0', '1', str1,)) # 默認將所有的0,替換爲1
print(re.sub('0', '1', str1, 1)) # 長度選 1,只替換從左到右第一個0
# 六:re.split的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
print(re.split('n', str1)) # 默認以所有n的位置來分割,返回結果不包含分隔符
print(re.split('n', str1, 2)) # 以字符串從左到右順序分割前兩個n,返回結果不包含分隔符
print(re.split('(n)', str1,)) # 若將分隔符加入group,那麼返回結果中也包括分隔符
# 七:re.escape(pattern)方法
# ===================================================
blog_url = 'https://blog.csdn.net/weixin_42444693'
print(re.escape(blog_url)) # 將文本(字符串)中所有可能被解釋爲正則運算符的字符進行轉義的應用函數。
# 八:re.compile(pattern,flags = 0)方法
# ===================================================
R_obj = re.compile('\d{2}') # 正則對象
print(R_obj.search('12abc').group()) # 12 通過調用group()方法得到匹配的字符串,如果字符串沒有匹配,則返回None。
print(R_obj.match('123abc')) # <re.Match object; span=(0, 1), match='12'>
print(R_obj.match('123abc').group()) # 12
# 九 Match對象下的.group()方法
# ===================================================
R_obj = re.compile('\d{2}') # 正則對象
print(type(R_obj.match('123abc'))) # <class 're.Match'>
print(R_obj.match('123abc').group()) # 12 ,str類型
# Match.group([ group1,... ] )
# 返回匹配項的一個或多個子組。如果有單個參數,則結果爲單個字符串;如果有多個參數,則結果是一個元組,每個參數有一個項目。沒有參數,group1默認爲零(返回整個匹配項)。如果groupN參數爲零,則對應的返回值是整個匹配字符串;否則,返回值爲0。如果它在包含範圍[1..99]中,則它是與相應括號組匹配的字符串。如果組號爲負或大於模式中定義的組數,IndexError則會引發異常。如果組包含在部分不匹配的模式中,則對應的結果爲None。如果在多次匹配的模式的一部分中包含一個組,則返回最後一個匹配項。
七、re模塊的常量(屬性)
屬性 | 別名 | 功能 |
---|---|---|
re.A | re.ASCII | 讓\w,\W,\b,\B,\d,\D,\s和\S 執行ASCII-只匹配完整的Unicode匹配代替。這僅對Unicode模式有意義,而對於字節模式則忽略。 |
re.I | re.IGNORECASE | 執行不區分大小寫的匹配;類似的表達式也[A-Z]將匹配小寫字母。 |
re.L | re.LOCALE | 讓\w,\W,\b,\B和區分大小寫的匹配取決於當前的語言環境。該標誌只能與字節模式一起使用。不建議使用此標誌,因爲語言環境機制非常不可靠,它一次只能處理一種“區域性”,並且僅適用於8位語言環境。默認情況下,Python 3中已爲Unicode(str)模式啓用了Unicode匹配,並且能夠處理不同的語言環境/語言。 |
re.M | re.MULTILINE | 指定時,模式字符’^‘在字符串的開頭和每行的開頭(緊隨每個換行符之後)匹配;模式字符’KaTeX parse error: Expected group after '^' at position 37: …行符之前)匹配。默認情況下,'^̲' 僅在字符串的開頭,字符串''的末尾和字符串末尾的換行符(如果有)之前立即匹配。 |
re.S | re.DOTALL | 使 ‘.’ 特殊字符與任何字符都匹配,包括換行符;沒有此標誌,’.’ 將匹配除換行符以外的任何內容。 |
八、練習題
import re
# 1. 驗證手機號碼:手機號碼的規則是以1開頭,第二位可以是34587,後面那9位就可以隨意了。
text = "18677889900"
result = re.match("1[34587]\d{9}",text)
print(result.group())
# 2. 驗證郵箱:郵箱的規則是郵箱名稱是用數字、英文字符、下劃線組成的,然後是@符號,後面就是域名了。
text = "[email protected]"
result = re.match("\w+@[a-z0-9]+\.[a-z]+",text)
print(result.group())
# 3. 驗證URL:URL的規則是前面是http或者https或者是ftp然後再加上一個冒號,再加上一個斜槓,再後面就是可以出現任意非空白字符了。
text = "https://blog.csdn.net/weixin_42444693"
result = re.match("(http|https|ftp)://\S+",text)
print(result.group())