1. 程式人生 > 其它 >Python知識小結------正則表示式

Python知識小結------正則表示式

技術標籤:Python正則表示式regexpython

一、前言

在平日的的文字查詢中,我們只要按下Crtl-F就可以進行內容查詢。而正則表示式則是將你要查詢的內容固定成為一個“模式”,我們在做查詢時會十分方便。

例如:我們要判斷一串數字是否為電話號碼時,使用正則表示式和不使用正則表示式的情況。我們知道電話號碼的模式是:400-555-4567

不使用正則表示式:

def isPhoneNumber(text):
    if len(text)!=12:   #判斷長度是否為12位
        return False
    for i in range(0,3):
        if not text[i].isdecimal():   #判斷前三位是否為數字
            return False
    if text[3]!='-':     #判斷第四位是否為‘-’
        return False
    for i in range(4,7):
        if not text[i].isdecimal():   #判斷5到7位是否為數字
            return False
    if text[7]!='-':                 #判斷第八位是否為‘-’
        return False
    for i in range(8,12):
        if not text[i].isdecimal():   #判斷9到12位是否為數字
            return False
    return True

使用正則表示式:

import re 
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search("400-555-4567")
if mo ==None:
    print("沒有找到")
else:
    print("匹配成功!"+mo.group())

首先從程式碼量來看,使用正則表示式的程式碼很簡潔,執行效率是很快的。而傳統程式碼需要對每一個字元進行判斷,其中多次使用if判斷和for迴圈,只要有一處有問題就會輸出fasle。如果資料量過大的話,其執行效率就會變低,因此使用正則表示式是十分有效的。

二、re模組簡介

聊到Python正則表示式的支援,首先肯定會想到 re 庫,這是一個Python處理文字的 標準庫。

標準庫 的意思表示這是一個 Python內建模組 ,不需要額外下載,目前Python內建模組大概有300個。可以在這裡檢視Python所有的內建模組:https://docs.python.org/3/py-modindex.html#cap-r

因為re是內建模組,所以不需要再下載,使用時直接引入即可:

import re

re模組官方文件:https://docs.python.org/zh-cn/3.8/library/re.html

三、常用的正則字元和規則

### 常用元字元 ###
1 .:匹配任何一個字元;
2 ^:匹配除去所列首個字元外的所有字元; ^\d表示必須以數字開頭。
3 $:匹配字串的尾部字元  \d$表示必須以數字結束
4 []:由一對方括號括起來的字元,表明一個字元集合,能夠匹配包含在其中的任意一個字元。’-‘ 減號來指定一個字元集合的範圍。例子:[a-zA-Z][^a-zA-Z]
5 | 將兩個規則並列起來,注意是匹配兩邊所有的規則 
    要匹配 ‘I have a dog’或’I have a cat’,需要寫成r’I have a (?:dog|cat)’ ,而不能寫成 r’I have a dog|cat’
5 (?: )  如果想限定它的有效範圍,必需使用一個無捕獲組 ‘(?: )’包起來
6 \d  匹配數字,這是一個以’\’開頭的轉義字元,’\d’表示匹配一個數字,即等價於[0-9]
7 \D 匹配非數字 這個是上面的反集,即匹配一個非數字的字元,等價於[^0-9]。注意它們的大小寫
   下面我們還將看到Python的正則規則中很多轉義字元的大小寫形式,代表互補的關係。
8 \w 匹配字母和數字 匹配所有的英文字母和數字,即等價於[a-zA-Z0-9]。 \W  等價 [^a-zA-Z0-9]
9 \s 匹配間隔符  即匹配空格符、製表符、回車符等表示分隔意義的字元,它等價於[ \t\r\n\f\v]。(注意最前面有個空格)  補集:  \S 
10 \A 匹配字串開頭  匹配字串的開頭。它和’^’的區別是,’\A’只匹配整個字串的開頭,即使在’M’模式下,它也不會匹配其它行的行首。
11 \Z 匹配字串結尾  匹配字串的結尾。它和’$’的區別是,’\Z’只匹配整個字串的結尾,即使在’M’模式下,它也不會匹配其它各行的行尾。
12 \b’ 匹配單詞邊界  它匹配一個單詞的邊界,比如空格等,不過它是一個‘0’長度字元,它匹配完的字串不會包括那個分界的字元。
       而如果用’\s’來匹配的話,則匹配出的字串中會包含那個分界符
13 \B 匹配非邊界 它同樣是個0長度字元。re.findall( r’\Bbc\w+’ , s )     #匹配包含’bc’但不以’bc’為開頭的單詞
    ['bcde']  #成功匹配了’abcde’中的’bcde’,而沒有匹配’bcd’
14 (?# ) 註釋 Python允許你在正則表示式中寫入註釋
### 重複 規則 ###
15 *   0或多次匹配  
16 +  1次或多次匹配  表示匹配前面的規則至少1次,可以多次匹配
17 ?  0或1次匹配 只匹配前面的規則0次或1次
### 精確匹配和最小匹配  ###
18 {m}    精確匹配m次
   {m,n}  匹配最少m次,最多n次。(n>m)  指定最少3次:{3,}  最大為5次:{,5}
    例子: re.findall( r’\b\d{3}\b’ , s )            # 尋找3位數
19 ‘*?’ ‘+?’ ‘??’ 最小匹配
   ‘*’ ‘+’ ‘?’通常都是儘可能多的匹配字元(貪婪匹配)。有時候我們希望它儘可能少的匹配。
   #例子 re.match(r'^(\d+)(0*)$', '102300').groups()  #('102300', '') 
   #     re.match(r'^(\d+?)(0*)$', '102300').groups() #('1023', '00')
   
### 前向界定與後向界定 ###
20 (?<=…) 前向界定  括號中’…’代表你希望匹配的字串的前面應該出現的字串。
    前向界定括號中的表示式必須是常值,也即你不可以在前向界定的括號裡寫正則式
    re.findall( r’(?<=[a-z]+)\d+(?=[a-z]+)' , s )          # 錯誤的用法
21 (?=…)  後向界定
   不過如果你只要找出後面接著有字母的數字,你可以在後向界定寫正則式:
   re.findall( r’\d+(?=[a-z]+)’, s )
22 (?<!...) 前向非界定
只有當你希望的字串前面不是’…’的內容時才匹配
23 (?!...) 後向非界定
只有當你希望的字串後面不跟著’…’內容時才匹配。
### 使用組 ###
24  ()    包含在’()’中的內容,而雖然前面和後面的內容都匹配成功了,卻並不包含在結果中,
    用group()或group(0)返回匹配的所有結果,用 group(1),(2)...返回第1,2...個()裡面的內容
25  (?(id/name)yes-pattern|no-pattern) 判斷指定組是否已匹配,執行相應的規則
    這個規則的含義是,如果id/name指定的組在前面匹配成功了,則執行yes-pattern的正則式,否則執行no-pattern的正則式。

四、簡單例項說明

首先明確建立正則表示式的步驟:

1.用import re 匯入正則表示式模組

2.用re.compile()函式建立一個Regex物件

3.向Regex物件的search()方法傳入想要查詢的字串。它會返回一個Match物件

4.呼叫Match物件的group方法,返回實際匹配文字的字串

1.普通正則表示式

import re
#定義一個變數來建立正則表示式
tmp = re.compile(r'hello')
s = tmp.search('goodbye bihao,hellhelowahaha')
if s == None:
    print("麼找到")
else:
    print("找到了\n"+s.group())

2.用管道匹配多個分組

字元|稱為“管道”。希望匹配許多個表示式中的一個時,就可以使用它。例如:正則表示式r'1234|yang 中將會匹配出'1234'或者'yang',如果1234和yang都出現在被查詢的字串中,那麼第一次匹配出來的文字將會作為Match物件返回。

import re
#管道匹配多個分組
src = re.compile(r'1234|yang')
mo1 = src.search(' yanghuaixu  1236712346534')
mo2 = src.search('1236712346534 yanghuaixu ')
if mo1 == None:
    print("mo1沒找到")
else:
    print("mo1找到了:"+mo1.group())
if mo2 == None:
    print("mo2中沒有找到")
else:
    print("mo2找打了:"+ mo2.group())

3.用問號實現可選匹配

有時候,想匹配的模式是可選的,此時需要使用到的符號是?,正則表示式中(wo)?部分表明,wo是可選擇的分組,如果要匹配的字串中有wo,則就匹配出來,如果沒有,就不匹配。所以次正則表示式既會匹配policeman,也會匹配policewoman 。

import re
#問號實現可選擇匹配
batRegx = re.compile(r'police(wo)?man')
img = batRegx.search('i am a policeman')
if img == None:
    print("沒找到img")
else:
    print("img找到了:"+img.group())
img1 = batRegx.search('i am a policewoman')
if img1 == None:
    print("img1沒找到")
else:
    print("img1找到了:"+img1.group())

4.用星號匹配零次或者多次

*意味著正則表示式“匹配零次或者多次”。即星號之前的分組,可以在文字中出現任意次。它可以完全不存在,或一次又一次的重複。則是wo在字串中出現幾次,就匹配幾次進行返回。

import re
#用星號匹配零次或者多次
emc = re.compile(r'(wo)*man')
mo2 = emc.search('hello everyone i am a policewoman')
mo3 = emc.search('helloeveryone i am a policewowowowowoman')
if mo2 ==None:
    print("沒找到")
else:
    print("mo2找到了:"+mo2.group())
if mo3 == None:
    print("沒找到")
else:
    print("mo3找到了:"+mo3.group())

5.用加號匹配一次或者多次

+意味著正則表示式“匹配一次或者多次,但至少要出現一次”。

import re
#用加號匹配一次或者多次
efc = re.compile(r'(wo)+man')
mo3 = efc.search('sdfsfdsadad policeman jiakwokak')
if mo3 == None:
    print("mo3沒找到")
else:
    print("mo3找到了:"+mo3.group())
mo4 = efc.search('adiaheiadhi am a policewowowoman hahahahhello')
if mo4 == None:
    print("mo4沒找見")
else:
    print("mo4找見了:"+ mo4.group())

6.findall()方法

除了search方法外,Regex物件也有一個findall()方法。search()方法將返回一個Match物件,包含被查詢字串中的"第一次"匹配的文字,而findall()方法將返回一組字串,包含所有符合匹配的字串。

import re
#findall方法
arg = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
print(arg.findall('400-200-3000 111-111-1111 456-890-0000 666-666-6666'))

7.字元分類

\d可以代表任何數字,也就是說\d是正則表示式(0|1|2|3|4|5|6|7|8|9)的縮寫。常見的字元分類如下表:

縮寫字元分類 表示
\d0到9的任何數字
\D除0到9的數字以外的任何字元
\w任何字母、數字或下劃線字元(可以認為是匹配"單詞"字元)
\W除字母、數字和下劃線以外的任何字元
\s空格、製表符和換行符(可以認為是匹配"空白"字元)
\S除空格、製表符和換行符以外的任何字元

import re
#字元分類
mmf = re.compile(r'\d+\s\w+')  #\d+表示匹配一個或多個數字,\s表示匹配一個空白字元,\w+表示匹配一個或多個 字母數字或下劃線
print(mmf.findall('1 hello,2,3 world,4aaa,5 _hello,6 HELLO,7 h_ello,8_heello,9 AA9AA'))

8.通配字元

.(句點)表示“萬用字元”。它可以匹配除了換行之外的所有字元。點-星萬用字元可以匹配所有的字串。

import re
#通配字元
mtr = re.compile(r'楊..')
print(mtr.findall('楊樹 楊梅 陽光 楊海明 洋洋得意'))

#用點-星匹配所有字元
mtt = re.compile(r'FirstName(.*) LastName(.*)')
mo6 = mtt.search('FirstName: Star LastName: Yang')
print(mo6.group(1))
print(mo6.group(2))

還有點-星萬用字元的“貪心”模式與“非貪心”模式:貪心模式會匹配到最後一個">"出現所包含的字串,非貪心模式會匹配到第一次">"出現所包含的字串

import re
#點-星貪心與非貪心模式:
#非貪心:
notanxin = re.compile(r'<.*?>')
mo7 = notanxin.search('<to server for> dinner>')
print(mo7.group())
#貪心:
tanxin = re.compile(r'<.*>')
mo8 = tanxin.search('<to server for> dinner> hello> 你好>')
print(mo8.group())