Python之re模塊

一、正則表達(dá)式

re模塊是python獨(dú)有的匹配字符串的模塊,該模塊中提供的很多功能是基于正則表達(dá)式實現(xiàn)的,
而正則表達(dá)式是對字符串進(jìn)行模糊匹配,提取自己需要的字符串部分,他對所有的語言都通用。

  • re模塊是python獨(dú)有的
  • 正則表達(dá)式所有編程語言都可以使用
  • re模塊、正則表達(dá)式是對字符串進(jìn)行操作
(一)常用正則

1、字符

元字符 匹配內(nèi)容
. 匹配除換行符以外的任意字符
\n 匹配一個換行符
\t 匹配一個制表符
^ 匹配字符串的開始
$ 匹配字符串的結(jié)尾
a|b 匹配字符a或字符b
[...] 匹配字符組中的字符
[^...] 匹配除了字符組中字符的所有字符
() 匹配括號內(nèi)的表達(dá)式,也表示一個組
(?:表達(dá)式) 取消括號的分組功能

2、字符集

正則 說明
\d 匹配數(shù)字,它相當(dāng)于類[0-9]
\D 匹配非數(shù)字,它相當(dāng)于類[^0-9]
\s 匹配任意的空白符,它相當(dāng)于類[\t\n\r\f\v]
\S 匹配非空白符,它相當(dāng)于類[^\t\n\r\f\v]
\w 匹配字母或數(shù)字或下劃線,它相當(dāng)于類[a-zA-Z0-9_]
\W 匹配非字母或數(shù)字或下劃線,它相當(dāng)于類[^a-zA-Z0-9_]
\b 匹配位于開始或結(jié)尾的空字符串
\B 匹配不位于開始或結(jié)尾的空字符串,它相當(dāng)于類[^\b]
\A 僅匹配字符串開頭,同^
\Z 僅匹配字符串結(jié)尾,同$

3、量詞
貪婪模式:總是嘗試匹配盡可能多的字符
非貪婪則相反,總是嘗試匹配盡可能少的字符。

量詞 用法說明
* 重復(fù)零次或更多次
+ 重復(fù)一次或更多次
? 重復(fù)零次或一次
{n} 重復(fù)n次
{n,} 重復(fù)n次至無限次
{n,m} 重復(fù)n到m次

{0,}匹配前一個字符0或多次,等同于*元字符
{+,}匹配前一個字符1次或無限次,等同于+元字符
{0,1}匹配前一個字符0次或1次,等同于?元字符
如果()后面跟的是特殊元字符如 (adc)* 那么*控制的前導(dǎo)字符就是()里的整體內(nèi)容,不再是前導(dǎo)一個字符

4、特殊分組用法表:只對正則函數(shù)返回對象的有用

用法 用法說明
(?P<name>) 分組起別名,?P<>定義組里匹配內(nèi)容的key(鍵),<>里面寫key名稱,值就是匹配到的內(nèi)容,用groupdict()打印字符串
(?P=name) 引用別名為<name>的分組匹配到字符串
\num 引用編號為num的分組匹配到字符串,第0組是整體
import re
#匹配出“<html><h1>[www.it123.com](http://www.it123.com/)</h1></html>”
ret = re.search(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.it123.com</h1></html>")
print(ret.group())
#<html><h1>www.it123.com</h1></html>
#先給兩個分組起了別名name1、name2,后邊引用這兩個別名,所以值要對應(yīng)起來
ret = re.search(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.it123.com</h2></html>")
print(ret.group())
#報錯‘NoneType’,因為h1和h2不對應(yīng)

a1='21abc11abc2'
a2= re.search(r"(\d)(\d)abc\2", a)
print(a2.group())
#21abc1
#\2表示前邊第二個分組

b1='21abc11abcabc2'
b2 = re.search(r"(?P<id>abc){2}", a)
print(b2 .group())
#abcabc

5、斷言
從斷言的表達(dá)形式可以看出,它用的就是分組符號,只不過開頭都加了一個問號,這個問號就是在說這是一個非捕獲組,這個組沒有編號,不能用來后向引用,只能當(dāng)做斷言。

用法 用法說明
(?=X) 正先行斷言。僅當(dāng)子表達(dá)式 X 在 此位置的右側(cè)匹配時才繼續(xù)匹配。例如,/w+(?=/d) 與后跟數(shù)字的單詞匹配,而不與該數(shù)字匹配。此構(gòu)造不會回溯。
(?!X) 負(fù)先行斷X言。僅當(dāng)子表達(dá)式 X 不在 此位置的右側(cè)匹配時才繼續(xù)匹配。例如,例如,/w+(?!/d) 與后不跟數(shù)字的單詞匹配,而不與該數(shù)字匹配 。
(?<=X) 正后發(fā)斷言。僅當(dāng)子表達(dá)式 X 在 此位置的左側(cè)匹配時才繼續(xù)匹配。例如,(?<=19)99 與跟在 19 后面的 99 的實例匹配。此構(gòu)造不會回溯。
(?<!X) 負(fù)后發(fā)斷言。僅當(dāng)子表達(dá)式 X 不在此位置的左側(cè)匹配時才繼續(xù)匹配。例如,(?<!19)99 與不跟在 19 后面的 99 的實例匹配

匹配<title>xxx</title>xxx(?<=<title>).*(?=</title>)
自己理解就是:

  1. 前兩種斷言要放在xxx的后邊寫:
    (1.1)(?=X): 表示xxx后邊有X
    (1.2)(?!X):表示xxx后邊沒有X
  2. 后兩種斷言要放在xxx的前邊寫:
    (2.1)(?<=X):表示xxx前邊有X
    (2.2)(?<!X):表示xxx前邊沒有X

5、例子
(1)非
^(?!.*200).*$,只匹配200
^(?!.*[200|400]).*$,只匹配200和400
[^a-z]反取,不含a-z字母的
(2)\u4e00-\u9fa5 中文
(3)r"\b([\u4e00-\u9fa5]\s?[\u4e00-\u9fa5]+)\b" # 小 明 匹配這種單字中間有空格的


二、re模塊

(一)原始字符 r的含義
  • 將在python里有特殊意義的字符如\b、\r,轉(zhuǎn)換成原生字符
  • 就是去除它在python的特殊意義,字符串里是啥就是啥,不會改變
a="\\hello\b\r"
b=r"\\hello\b\r"
print(a)
print(b)
# \hello
#\\hello\b\r
(二)正則匹配模式表
修飾符 描述
re.I(re.IGNORECASE) 使匹配對大小寫不敏感
re.L(re.LOCALE) 做本地化識別(locale-aware)匹配
re.M(re.MULTILINE) 多行匹配,影響 ^ 和 $
re.S(re.DOTALL) 使 . 匹配包括換行在內(nèi)的所有字符
re.U 根據(jù)Unicode字符集解析字符。這個標(biāo)志影響 \w, \W, \b, \B.
re.X 該標(biāo)志通過給予你更靈活的格式以便你將正則表達(dá)式寫得更易于理解。
(三)函數(shù)
1、re.compile(pattern[, flags])

compile 函數(shù)用于編譯正則表達(dá)式,生成一個正則表達(dá)式( Pattern )對象,供 match() 和 search() 這兩個函數(shù)使用

  • pattern : 一個字符串形式的正則表達(dá)式
  • flags :可選,表示匹配模式,比如忽略大小寫,多行模式等具體為:re.I、re.L 、re.M 、re.S 、re.U 、re.X
2、re.match(pattern, string, flags=0)

match 嘗試從字符串的起始位置匹配一個模式,如果不是起始位置匹配成功的話,返回none。

  • pattern:匹配的正則表達(dá)式
  • string:要匹配的字符串。
  • flags : 可選,表示匹配模式
3、re.search(pattern, string, flags=0)

search 掃描整個字符串并返回第一個成功的匹配。

  • pattern :匹配的正則表達(dá)式
  • string:要匹配的字符串。
  • flags : 可選,表示匹配模式

re.match與re.search的區(qū)別:

  • re.match只匹配字符串的開始位置,如果字符串開始不符合正則表達(dá)式,則匹配失敗,函數(shù)返回None;
  • re.search匹配整個字符串,直到找到一個匹配。
4、 re.sub(pattern, repl, string, count=0, flags=0)

正則表達(dá)式替換函數(shù)

  • pattern:匹配的正則表達(dá)式
  • repl:需要替換成的字符串或函數(shù)
  • string:需要被替換的字符串
  • count:替換次數(shù)
  • flags:匹配模式
  • 特殊用法:\數(shù)字\g<數(shù)字>表示前面pattern里面第數(shù)字個分組,需要和r'\數(shù)字'聯(lián)用,否則不好用,\g<0>,\0代表前面pattern匹配到的所有字符串。
import re
text="2020年10月14日"
text=re.sub(r"[\u4e00-\u9fa5]","-",text,2).strip("日")
#2020-10-14

c= 'abc124hello46goodbye67shit'
c=re.sub(r'\d+[hg]', 'foo1', c)
# abcfoo1ellofoo1oodbye67shit

a1 = re.sub('(\d{2})-(\d{2})-(\d{4})', r'\3-\1-\2', '06-07-2018')
a2 = re.sub('(\d{2})-(\d{2})-(\d{4})', r'\g<3>-\g<2>-\g<1>', '06-07-2018')
a3 = re.sub(r'(\d{4})(\d{2})(\d{2})', r'\1-\2-\3', '20201010')
#a1=2018-06-07
#a2=2018-06-07
#a3=2020-10-10
def replace_num(str):
    numDict = {
        "0": "〇",
        "1": "一",
        "2": "二",
        "3": "三",
        "4": "四",
        "5": "五",
        "6": "六",
        "7": "七",
        "8": "八",
        "9": "九",
    }
    #要用.group()取文本,因為是匹配出來的是對象
    print(str.group())
    return numDict[str.group()]
my_str = "2018年6月7號"
a = re.sub(r"(\d)", replace_num, my_str)
print(a)  
# 二〇一八年六月七號,每次匹配一個數(shù)字,執(zhí)行函數(shù),獲取替換后的值
#匹配多行
def process(text):
    import re
    if "|STCNTTTP|" in text:
        text=re.sub("\|STCNTTTP\|.*option.*\|STCNTTTP\|","",text,flags=re.DOTALL)
    return text
4.1、subn(pattern, repl, string, count=0, flags=0)

替換匹配成功的指定位置字符串,并且返回替換次數(shù),可以用兩個變量分別接受

  • pattern: 正則模型
  • repl : 要替換的字符串
  • string : 要匹配的字符串
  • count : 指定匹配個數(shù)
  • flags : 匹配模式
import re
origin = "hello alex bcd alex lge alex acd 19"
a,b = re.subn("a","替換",origin) 
print(a)
print(b)
#hello 替換lex bcd 替換lex lge 替換lex 替換cd 19
#4
5、re.split(pattern, string, maxsplit=0)
  • 多個 分隔符,切割功能非常強(qiáng)大
  • 通過正則表達(dá)式將字符串分離。
  • 如果用括號將正則表達(dá)式括起來,那么匹配的字符串也會被列入到list中返回。
  • maxsplit是分離的次數(shù),maxsplit=1分離一次,默認(rèn)為0,不限制次數(shù)。
    (1) 單字符切割:
re.split(';',line)
['aa bb cc dd', ' ee ff. gg- hh ii kk']

(2) 兩個字符以上切割,放在 [ ]中(不保留分隔符):

re.split('[;.-]',line)
['aa bb cc dd', ' ee ff', ' gg', ' hh ii kk']

(3) 使用( )捕獲分組(保留分割符):

re.split('([;,])',line)
['aa bb cc dd', ';', ' ee ff', '.', ' gg', '-', ' hh ii kk']
def process(text):
    """
    eg:安徽省住房和城鄉(xiāng)建設(shè)廳黨組書記、廳長  趙馨群
    eg:省工商局局長 朱斌  省商務(wù)廳副廳長 喬興力
    空格分割,多個的,長多于3的不要
    """
    import re
    res=text.split()
    print(res)
    if len(res)>1:
        return [i.replace(" ", "") for i in res if 1 < len(i) < 4]
    if len(res)==1:
        return [i.replace(" ", "") for i in res]
    else:
        return text
6、findall(string[, pos[, endpos]])

在字符串中找到正則表達(dá)式所匹配的所有子串,并返回一個列表,如果沒有找到匹配的,則返回空列表。
注意: match 和 search 是匹配一次 ,findall 匹配所有。

  • string : 待匹配的字符串。
  • pos : 可選參數(shù),指定字符串的起始位置,默認(rèn)為 0。
  • endpos : 可選參數(shù),指定字符串的結(jié)束位置,默認(rèn)為字符串的長度。

用法:

  • 1、無分組:匹配所有合規(guī)則的字符串,匹配到的字符串放到一個列表中
  • 2、有分組:只將匹配到的字符串里,組的部分放到列表里返回(相當(dāng)于groups()方法)
  • 3、多個分組:只將匹配到的字符串里,組的部分放到一個元組中,最后將所有元組放到一個列表里返(相當(dāng)于在group()結(jié)果里再將組的部分,分別,拿出來放入一個元組,最后將所有元組放入一個列表返回)
  • 4、分組中有分組:只將匹配到的字符串里,組的部分放到一個元組中,先將包含有組的組,看作一個整體也就是一個組,把這個整體組放入一個元組里,然后在把組里的組放入一個元組,最后將所有組放入一個列表返回(只要是個組就把結(jié)果放元組里,有幾個組,元組里就有幾個)
  • 5、?: 在有分組的情況下findall()函數(shù),不只拿分組里的字符串,拿所有匹配到的字符串,注意?:只用于不是返回正則對象的函數(shù)如findall()
import re
#1無分組
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("a\w+", origin)
print(r)
#輸出結(jié)果
#['alex', 'alex', 'alex', 'acd']

#2有分組
r = re.findall("a(\w+)", origin)    
print(r)
#輸出結(jié)果
#['lex', 'lex', 'lex', 'cd']

#3多個分組
r = re.findall("(a)(\w+)", origin)
print(r)
#輸出結(jié)果
#[('a', 'lex'), ('a', 'lex'), ('a', 'lex'), ('a', 'cd')]

#4分組中有分組
r = re.findall("(a)(\w+(e))", origin)    
print(r)
#輸出結(jié)果
#[('a', 'le', 'e'), ('a', 'le', 'e'), ('a', 'le', 'e')]

#5?:
b = re.findall("a(?:\w+)",origin) 
print(b)
#輸出
# ['alex', 'alex', 'alex', 'acd']

#findall匹配多個值,取值
def process(text):
    import re
    l=re.findall(r"javascript:download\('\./(.*?\.pdf)','(.*?\.pdf)'\);",text)
    ptf_l=list(l[0])
    url=f"https://www.shclearing.com/wcm/shch/pages/client/download/download.jsp?FileName={ptf_l[0]}&DownName={ptf_l[1]}"
    print(url)
process("javascript:download('./P020200729557188212660.pdf','漳州市九龍江集團(tuán)有限公司關(guān)于主體信用評級發(fā)生變化的公告.pdf');")
#獲取到的l是元組的格式

注意1:一旦匹配成,再次匹配,是從前一次匹配成功的,后面一位開始的,也可以理解為匹配成功的字符串,不在參與下次匹配

import re
#無分組
r = re.findall("\d+\w\d+", "a2b3c4d5")    #瀏覽全部字符串,匹配所有合規(guī)則的字符串,匹配到的字符串放到一個列表中
print(r)
#輸出結(jié)果
#['2b3', '4d5']
#注意:匹配成功的字符串,不在參與下次匹配,所以3c4也符合規(guī)則但是沒匹配到

注意2:如果沒寫匹配規(guī)則,也就是空規(guī)則,返回的是一個比原始字符串多一位的,空字符串列表

import re
#無分組
r = re.findall("", "a2b3c4d5")    #瀏覽全部字符串,匹配所有合規(guī)則的字符串,匹配到的字符串放到一個列表中
print(r)
#輸出結(jié)果
#['', '', '', '', '', '', '', '', '']
#注意:如果沒寫匹配規(guī)則,也就是空規(guī)則,返回的是一個比原始字符串多一位的,空字符串列表 

注意3:正則匹配到空字符的情況,如果規(guī)則里只有一個組,而組后面是*就表示組里的內(nèi)容可以是0個或者多過,這樣組里就有了兩個意思:
一個意思是匹配組里的內(nèi)容,
二個意思是匹配組里0內(nèi)容(即是空白)
所以盡量避免用*否則會有可能匹配出空字符串

import re
origin = "hello alex bcd alex"
r = re.findall("(a)*", origin)   
print(r)
#['', '', '', '', '', '', 'a', '', '', '', '', '', '', '', '', 'a', '', '', '', '']
7、方法

正則表達(dá)式,返回類型為表達(dá)式對象的
如:<_sre.SRE_Match object; span=(6, 7), match='a'>
返回對象的,需要用正則方法取字符串,

  • group():group() 同group(0)就是匹配正則表達(dá)式整體結(jié)果,不管有沒有分組將匹配到的全部拿出來
  • group(num>0):返回匹配到的對應(yīng)第num個分組結(jié)果
  • groups() :返回所有分組匹配的列表 =(group(1),group(2).....)
  • groupdict() :只返回分組中定義了key的組的結(jié)果
  • start() :返回匹配開始的位置
  • end() :返回匹配結(jié)束的位置
  • span() :返回一個元組包含匹配 (開始,結(jié)束) 的位置
import re
#無分組
origin = "hello alex bcd alex lge alex acd 19"
r = re.search("a\w+", origin)   
r1 = re.search("a(\w+).*(\d)", origin) 
r2 = re.search("a(?P<n1>\w+).*(?P<n2>\d)", origin)
# group獲取匹配到的所有結(jié)果,不管有沒有分組將匹配到的全部拿出來
print(r.group())     
print(r1.group())   
print(r1.group(2))  
print(r2.group()) 
 # groups獲取模型中匹配到的分組結(jié)果,只拿出匹配到的字符串中分組部分的結(jié)果
print(r.groups())   
print(r1.groups())    
print(r2.groups())   
# 獲取模型中匹配到的分組結(jié)果,只拿出匹配到的字符串中分組部分定義了key的組結(jié)果
print(r.groupdict()) 
print(r1.groupdict()) 
print(r2.groupdict()) 
r3 = re.search("(h).*a(?P<n1>\w+).*(?P<n2>\d)", origin)
print(r3.groupdict()) 
#alex
#alex bcd alex lge alex acd 19
#9
#alex bcd alex lge alex acd 19

#()
#('lex', '9')
#('lex', '9')

#{}
#{}
#{'n1': 'lex', 'n2': '9'}
#{'n1': 'cd', 'n2': '9'}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 不必羨慕那些活的精彩快樂的人,他們其實并不比你優(yōu)秀,他們只是減輕了對他人高度的感受性;從而活在自己的節(jié)奏里面; 也...
    BeautifulSoulpy閱讀 576評論 0 0
  • 以下示例所使用 python 版本為: 3.7 python 提供 re 模塊,來滿足正則表達(dá)式的使用。在開始介紹...
    zhipingChen閱讀 1,978評論 0 3
  • 01. 正則表達(dá)式基礎(chǔ)知識 1.1 原子 原子是正則表達(dá)式中最基本的組成單位,每個正則表達(dá)式中至少要包含一個原子,...
    莫忘初心_倒霉熊閱讀 628評論 0 3
  • 什么是正則表達(dá)式 ? 一組特殊符號組成的表達(dá)式,用于描述某種規(guī)則。該應(yīng)用場景生活中隨處可見。 ? 例如:讓...
    徐弱西閱讀 2,213評論 0 1
  • 前面已經(jīng)初步介紹了正則式的語法規(guī)則和re模塊的方法。這次主要舉了幾個例子,看看re模塊在實際工作中的使用。 1. ...
    0893051f5f11閱讀 16,864評論 0 8

友情鏈接更多精彩內(nèi)容