Python必學模塊之re模塊(正則表達式)詳解


一、什麼是正則表達式

通俗理解:

按照一定的規則,從某個字符串中匹配出想要的數據。這個規則就是正則表 達式。

官方參考:正則表達式

二、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(patternflags = 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())

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章