Python正則表達式詳解


一、什么是正則表達式

正則表達式(Regular expression)是一組由字母和符號組成的特殊文本, 它可以用來從文本中找出滿足你想要的格式的句子。

比如我們在網站中看到對用戶名規則做出了如下限制:只能包含小寫字母、數字、下划線和連字符,並且限制用戶名長度在3~15個字符之間,如何驗證一個用戶名是否符合規則呢 ?我們使用以下正則表達式:

以上的正則表達式可以接受john_doe、jo-hn_doe、john12_as,但不能匹配A1,因為它包含了大寫字母而且長度不到3個字符

1.1 re.compile

compile:re.compile是將正則表達式轉換為模式對象,這樣可以更有效率匹配。使用compile轉換一次之后,以后每次使用模式時就不用進行轉換
pattern:寫正則表達式
flags:匹配模式

從compile()函數的定義中,可以看出返回的是一個匹配對象,它單獨使用就沒有任何意義,需要和findall(), search(), match()搭配使用。
compile()與findall()一起使用,返回一個列表。

# compile配合findall
import re
a = '0355-67796666'
b = re.compile(r'\d+-\d{8}')
r = re.findall(b,a)
print(r)

import re
a = '0355-67796666'
b = re.compile(r'\d+-\d{8}')
r = b.findall(a)
print(r)

# 直接使用findall
import re
a = '0355-67796666'
r = re.findall(r'\d+-\d{8}',a)
print(r)

# compile配合search
import re
a = '0355-67796666'
正則 = re.compile(r'\d+-\d{8}')
r = re.search(正則,a)
print(r.group())

# compile配合match
import re
a = '0355-67796666'
正則 = re.compile(r'\d+-\d{8}')
r = re.match(正則,a)
print(r.group())

1.2 re.match

match 從字符串的第一個字符開始匹配,如果未匹配到返回None,匹配到則返回一個對象

match判斷正則表達式是否從開始處(首字母)匹配一個字符串,例如第一個不是\d(數字),返回None

import re
a = 'A83C72D1D8E67'
r = re.match('\d',a)
print(r) # 返回對象所在位置
print(r.group()) # 返回找到的結果,例如8
print(r.span()) # 返回一個元組表示匹配位置(開始,結束)

1.3 re.search

Search與match有些類似,只是搜索整個字符串然后第一個匹配到指定的字符則返回值,未匹配到則返回None。獲取值得方法也需要通過group()
從字符串開始往后匹配,一匹配到則返回一個對象。需要通過group來獲取匹配到的值。

search 遍歷字符串,找到正則表達式匹配的第一個位置

import re
a = 'A83C72D1D8E67'
r = re.search('\d',a)
print(r)
print(r.group())

1.4 re.findall

Findall是匹配出字符串中所有跟指定值有關的值,並且以列表的形式返回。未匹配到則返回一個空的列表。匹配出指定字符的所有值,並以列表返回值。

二、簡單的模式:字符匹配

元字符 描述
. 句號匹配任意單個字符除了換行符
[] 字符種類,匹配方括號內的任意字符,中括號內每個字符是或(or)****的關系
[^] 否定的字符種類,匹配除了方括號里的任意字符
***** 匹配0次或無限次,重復在*****號之前的字符
+ 匹配1次或無限次,重復在+號之前的字符
? 匹配0次或1次,重復在?號之前的字符
{n,m} 匹配num個大括號之前的字符(n<=num<=m)
(xyz) 字符集又稱做,匹配與xyz完全相等的字符串,每個字符是且(and)****的關系
| 或運算符,匹配符號前或后的字符
** 轉義字符,用於匹配一些保留字符 [ ]、( )、{ }、. 、 * 、+ 、? 、^ 、$、\ 、|
^ 從字符串開始位置開始匹配
$ 從字符串末端開始匹配

反斜杠后面跟普通字符實現特殊功能

特殊字符 描述
\d 匹配數字,相當於[0-9]
\D 不匹配數字,相當於[^0-9]
\s 匹配空白字符(包括空格、換行符、制表符等),相當於 [\t\n\r\f\v]
\S 與\s相反,相當於 [^\t\n\r\f\v]
\w 匹配中文,下划線,數字,英文,相當於[a-zA-z0-9_]
\W 與\w相反,匹配特殊字符,如$、&、空格、\n、\t等
\b 匹配單詞的開始或結束
\B 與\b相反

2.1 元字符

# 提取字符串a中所有的數字,返回結果:['7', '6', '3', '6']
import re
a = '孫悟空7豬八戒6沙和尚3唐僧6白龍馬'
r = re.findall('[0-9]',a)
print(r)

# 提取字符串a中所有非數字,返回:['孫', '悟', '空', '豬', '八', '戒', '沙', '和', '尚', '唐', '僧', '白', '龍', '馬']
import re
a = '孫悟空7豬八戒6沙和尚3唐僧6白龍馬'
r = re.findall('[^0-9]',a)
print(r)

# 找到字符串中間字母是d或e的單詞,返回:['xdz', 'xez']
import re
a = 'xyz,xcz,xfz,xdz,xaz,xez'
r = re.findall('x[de]z',a)
print(r)

# 找到字符串中間字母不是d或e的單詞,返回:['xyz', 'xcz', 'xfz', 'xaz']
import re
a = 'xyz,xcz,xfz,xdz,xaz,xez'
r = re.findall('x[^de]z',a)
print(r)

# 找到字符串中間字母是d或e或f的單詞,返回:['xfz', 'xdz', 'xez']
import re
a = 'xyz,xcz,xfz,xdz,xaz,xez'
r = re.findall('x[d-f]z',a)
print(r)

2.2 概括字符集

# 提取字符串a中所有的數字
import re
a = 'Excel 12345Word\n23456_PPT12lr'
r = re.findall('\d',a)
print(r)
# 提取字符串a中所有非數字
import re
a = 'Excel 12345Word\n23456_PPT12lr'
r = re.findall('\D',a)
print(r)

# \w 可以提取中文,英文,數字和下划線,不能提取特殊字符
import re
a = 'Excel 12345Word\n23456_PPT12lr'
r = re.findall('\w',a)
print(r)

# \W 提取特殊字符、空格、\n、\t等
import re
a = 'Excel 12345Word\n23456_PPT12lr'
r = re.findall('\W',a)
print(r)


2.3 數量詞

# 提取大小寫字母混合的單詞
import re
a = 'Excel 12345Word23456PPT12Lr'
r = re.findall('[a-zA-Z]{3,5}',a)
print(r)
# 貪婪與非貪婪 【Python默認使用貪婪模式】
貪婪:'[a-zA-Z]{3,5}'
# 先找三個連續的字母,最多找到5個連續的字母后停止。在3個以后且5個以內發現了不是子母的也停止。
非貪婪:'[a-zA-Z]{3,5}?'或'[a-zA-Z]{3}'
建議使用后者,不要使用?號,否則你會與下面的?號混淆
# 匹配0次或無限多次*號,*號前面的字符出現0次或無限次
import re
a = 'exce0excell3excel3'
r = re.findall('excel*',a)
print(r)

# 匹配1次或者無限多次+號,+號前面的字符至少出現1次
import re
a = 'exce0excell3excel3'
r = re.findall('excel+',a)
print(r)
# 匹配0次或1次 ?號,?號經常用來去重復
import re
a = 'exce0excell3excel3'
r = re.findall('excel?',a)
print(r)

2.4 邊界匹配^和$

# 限制電話號碼的位置必需是8-11位才能提取
import re
tel = '13811115888'
r = re.findall('^\d{8,11}$',tel)
print(r)

2.5 組( )

# 將abc打成一個組,{2}指的是重復幾次,匹配abcabc
import re
a = 'abcabcabcxyzabcabcxyzabc'
r = re.findall('(abc){2}',a)
print(r)

可以加入很多個組

2.6 匹配模式參數

# findall第三參數re.I忽略大小寫
import re
a = 'abcFBIabcCIAabc'
r = re.findall('fbi',a,re.I)
print(r)
# 多個模式之間用| 連接在一起
import re
a = 'abcFBI\nabcCIAabc'
r = re.findall('fbi.{1}',a,re.I | re.S) # 匹配fbi然后匹配任意一個字符包括\n
print(r)

注:.句號,不匹配\n,但是使用re.S之后,匹配所有字符包括換行符
1).re.I(re.IGNORECASE): 忽略大小寫
2).re.M(MULTILINE): 多行模式,改變’^’和’$’的行為
3).re.S(DOTALL): 點任意匹配模式,改變’.’的行為
4).re.L(LOCALE): 使預定字符類 \w \W \b \B \s \S 取決於當前區域設定
5).re.U(UNICODE): 使預定字符類 \w \W \b \B \s \S \d \D 取決於unicode定義的字符屬性
6).re.X(VERBOSE): 詳細模式。這個模式下正則表達式可以是多行,忽略空白字符,並可以加入注釋

2.7 re.sub替換字符串

# 把FBI替換成BBQ
import re
a = 'abcFBIabcCIAabc'
r = re.sub('FBI','BBQ',a)
print(r)
# 把FBI替換成BBQ,第4參數寫1,證明只替換第一次,默認是0(無限替換)
import re
a = 'abcFBIabcFBIaFBICIAabc'
r = re.sub('FBI','BBQ',a,1)
print(r)
注意:雖然字符串的內置方法 字符串.replace 也可以進行替換,但是正則表達式更強大
# 拓展知識
import re
a = 'abcFBIabcFBIaFBICIAabc'
def 函數名(形參):
pass
r = re.sub('FBI',函數名,a,1)
print(r)

分析:如果找到了FBI這個子串,會將FBI當成參數傳到形參中,pass是什么都沒返回,所以FBI被空字符串代替了。

# 把函數當參數傳到sub的列表里,實現把業務交給函數去處理,例如將FBI替換成$FBI$
import re
a = 'abcFBIabcFBIaFBICIAabc'
def 函數名(形參):
	分段獲取 = 形參.group() # group()在正則表達式中用於獲取分段截獲的字符串,獲取到FBI
	return '$' + 分段獲取 + '$'
r = re.sub('FBI',函數名,a)
print(r)

2.8 把函數做為參數傳遞

# 將字符串中大於等於5的替換成9,小於5的替換成0
import re
a = 'C52730A52730D52730'
def 函數名(形參):
    分段獲取 = 形參.group()
    ifint(分段獲取) >= 5:
    	return'9'
else:
	return '0'
r = re.sub('\d',函數名,a)
print(r)

2.9 group分組

import re
a = "123abc456"
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0) #123abc456,返回整體
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1) #123
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2) #abc
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3) #456
  1. 正則表達式中的三組括號把匹配結果分成三組
    group() 同group(0)就是匹配正則表達式整體結果
    group(1) 列出第一個括號匹配部分,group(2) 列出第二個括號匹配部分,group(3) 列出第三個括號匹配部分。

  2. 沒有匹配成功的,re.search()返回None

  3. 當然正則表達式中沒有括號,group(1)肯定不對了。

    import re
    a = 'life is short,i use python'
    r = re.search('life(.*)python',a)
    print(r.group(1))
    

    等同於

    import re
    a = 'lifeis short,i use python'
    r = re.findall('life(.*)python',a)
    print(r)
    
    # 拓展知識
    import re
    a = 'life is short,i use python,i love python'
    r = re.search('life(.*)python(.*)python',a)
    print(r.group(0)) # 完整正則匹配
    print(r.group(1)) # 第1個分組之間的取值
    print(r.group(2)) # 第2個分組之間的取值
    print(r.group(0,1,2))# 以元組形式返回3個結果取值
    print(r.groups()) # 返回就是group(1)和group(2)
    

三、正則表達式的一些建議

1、常用的正則表達式,不用自己寫,在百度上搜索常用正則表達式,不要重復造輪子
2、如果內置方法可以快速解決問題,建議不要化簡為繁

附1:正則表達式基礎語法

d 指出一個字符串的開始
$ 指出一個字符串的結束
\ 將下一個字符標記為一個特殊字符、或一個原義字符、或一個向后引用、或一個八進制轉義符
^abc 匹配所有以 "abc" 開始的字符串 (例如:"abc","abccba")
abc$ 匹配所有以"abc" 結尾的字符串 (例如:"gggabc","reddcba")
^abc$ 匹配開始和結尾都為"abc"的字符串 (例如:"abc")
abc 沒有任何字符,匹配任何包含"abc"的字符串 (例如:"aaaabccc","abc123")
n 匹配n "\n":匹配換行符 "/"這里是 \he / 連在一起寫,匹配 " / " 字符
* 匹配前面的子表達式零次或多次
+ 匹配前面的子表達式一次或多次
? 匹配前面的子表達式零次或一次
ac* 匹配字符串其中一個a后面跟着零個或若干個c (例如:"accc","abbb")
ac+ 匹配字符串其中一個a后面跟着至少一個c或者多個 (例如:"ac","acccccccc")
ac? 匹配字符串其中一個a后面跟着零個或者一個c (例如:"a","ac")
a?c+$ 匹配字符串的末尾有零個或一個a跟着一個或多個c (例如:"ac","acccccc",''c'',"ccccccc")
n為非負整數,匹配n次
n為非負整數,匹配至少n次
n,m為非負整數,最少匹配n次 最多匹配m次
ab 表示一個字符串有一個a后面跟隨2個b (例如:"abb","abbbbb")
ab 表示一個字符串有一個a后面跟隨至少2個b (例如:"abb","abbb")
ab 表示一個字符串有一個a后面跟隨3到6個b (例如:"abbb","abbbb","abbbb")
| 表示"或"
. 表示任何字符
a|b 表示一個字符串里有 a 或者 b (例如:"a","b","ab","abc")
a. 表示一個字符串有一個 a 后面跟着一個任意字符 (例如:"a1","a456","avv")

附2:方括號里用"^"表示不希望出現的字符

[abc] 表示字符集合,表示一個字符串有一個"a"或"b"或"c" 等價於 [z|b|c]
[^abc] 表示一個字符串中不應該出現abc,即是匹配未包含改集合的任意字符
[a-z] 表示一個字符串中存在一個a和z之間的所有字母
[0-9] 表示一個字符串中存在一個0和9之間的所有數字
[^a-z] 表示一個字符串中不應該出現a到z之間的任意一個字母
[1] 表示一個字符串中以字母開頭
[0-9]% 表示一個百分號前有一個的數字;

附3:由字符''和另一個字符組成特殊含義

匹配一個數字字符,等價[0-9] \d
匹配一個非數字字符,等價[^0-9] \D
匹配一個換頁符,等價\x0c和\cL \f
匹配一個換行符。等價於\x0a和\cJ \n
匹配一個回車符。等價於\x0d和\cM \r
匹配任何空白字符,包括空格、制表符、換頁符等等。等價於[ \f\n\r\t\v] \s
匹配任何非空白字符。等價於[^ \f\n\r\t\v] \S

關注公眾號【紫電的學習筆記】,回復【正則表達式】獲取PDF資料


  1. a-zA-Z ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM