Python3.5筆記——第11章 正則表達(dá)式

Python3.5筆記

第11章 正則表達(dá)式

認(rèn)識正則表達(dá)式

正則表達(dá)式是一個特殊字符序列,能夠幫助用戶檢查一個字符串是否與某種格式匹配,從而達(dá)成快速檢索或替換某個格式、規(guī)則的文本。Python自1.5版本增加了re模塊。

表1:特殊字符在正則表達(dá)式中的應(yīng)用

實(shí)例 描述
. 匹配除了“\n”之外的任何字符。如果要匹配包括“\n”的任意字符,請使用如‘[.\n]’的模式
\d 匹配一個數(shù)字字符,等價于[0-9]
\D 匹配一個非數(shù)字字符,等價于[^0-9]
\s 匹配任意空白字符,包括空格、制表符、換頁符等。等價于[\f\n\r\t\v]
\S 匹配任意非空白字符,等價于[^\f\n\r\t\v]
\w 匹配包括下劃線的任意單詞字符,等價于[A-Za-z0-9_]
\W 匹配任意非單詞字符,等價于[^A-Za-z0-9_]

表2:字符類在正則表達(dá)式中的作用

實(shí)例 描述
[Pp]ython 匹配Python和python
rub[ye] 匹配ruby和rube
[aeiou] 匹配中括號內(nèi)的任意一個字母
[0-9] 匹配任意數(shù)字,類似于[0123456789]
[a-z] 匹配任意小寫字母
[A-Z] 匹配任意大寫字母
[a-zA-Z0-9] 匹配任意大寫字母小寫字母數(shù)字
[^aeiou] 除了aeiou字母以下的所有字符
[^0-9] 匹配除了數(shù)字外的字符

在正則表達(dá)式中,如果直接給出字符,就是精確匹配。從表1可知,用\d可以匹配一個數(shù)字,用\w可以匹配一個數(shù)字或字母。例如:

  • '00\d'可以匹配'007',但無法匹配'00q'
  • '\d\d\d'可以匹配'123'
  • '\w\w\d'可以匹配'py3'
  • .可以匹配任意字符,所以'py.'可以匹配'pyc''pyo''py!'等

在正則表達(dá)式中,要匹配變長的字符,可以用*表示任意個數(shù)的字符(包括0個),用+表示至少一個字符,用?表示0個或1個字符,用{n}表示n個字符,用{n,m}表示n-m個字符。下面來看一個復(fù)雜的例子。

\d{3}\s+\d{3,8}

長度是3的數(shù)字,如:010;至少1個空白字符;3到8個數(shù)字,如:'1234567',綜上所述,正則表達(dá)式可以匹配以任意個數(shù)的空格隔開的帶區(qū)號的電話號碼。

如果要匹配'010-12345'這樣的號碼呢?由于‘-’是特殊字符,正則表達(dá)式中用'\'轉(zhuǎn)義,因此用正則表達(dá)式可以表示為:

\d{3}\-\d{3,8}

要更精確的匹配,可以用[]表示范圍。例如:

  • [0-9a-zA-Z_]可以匹配數(shù)字、字母或下劃線。
  • [0-9a-zA-Z_]+可以匹配至少有一個數(shù)字、字母或下劃線組成的字符串。
  • [a-zA-Z_][0-9a-zA-Z_]*可以匹配由大小寫字母下劃線開頭,后面接任意個數(shù)的數(shù)字大小寫字母及下劃線組成的字符串。也就是python的合法變量。
  • [a-zA-Z][0-9a-zAO-Z_]{0,19}同上,只是更精確的限制了變量的長度個數(shù)是1-20個字符(前面1個字符加后面19個字符)
  • A|B用于匹配A或B
  • 表示行的開頭,\d表示必須以數(shù)字開頭
  • $表示表示行的結(jié)束,\d$表示必須以數(shù)字結(jié)束。

正則表達(dá)式模式

模式字符串使用特殊的語法來表示一個正則表達(dá)式:

字母和數(shù)字表示他們自身。一個正則表達(dá)式模式中的字母和數(shù)字匹配同樣的字符串。

多數(shù)字母和數(shù)字前加一個反斜杠時會擁有不同的含義。

標(biāo)點(diǎn)符號只有被轉(zhuǎn)義時才匹配自身,否則它們表示特殊的含義。

反斜杠本身需要使用反斜杠轉(zhuǎn)義。

由于正則表達(dá)式通常都包含反斜杠,所以你最好使用原始字符串來表示它們。模式元素(如 r'\t',等價于 '\t')匹配相應(yīng)的特殊字符。

下表列出了正則表達(dá)式模式語法中的特殊元素。如果你使用模式的同時提供了可選的標(biāo)志參數(shù),某些模式元素的含義會改變。

模式 描述
^ 匹配字符串的開頭
$ 匹配字符串的末尾。
. 匹配任意字符,除了換行符,當(dāng)re.DOTALL標(biāo)記被指定時,則可以匹配包括換行符的任意字符。
[...] 用來表示一組字符,單獨(dú)列出:[amk] 匹配 'a','m'或'k'
[^...] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re* 匹配0個或多個的表達(dá)式。
re+ 匹配1個或多個的表達(dá)式。
re? 匹配0個或1個由前面的正則表達(dá)式定義的片段,非貪婪方式
re{ n} 精確匹配 n 個前面表達(dá)式。例如, o{2} 不能匹配 "Bob" 中的 "o",但是能匹配 "food" 中的兩個 o。
re{ n,} 匹配 n 個前面表達(dá)式。例如, o{2,} 不能匹配"Bob"中的"o",但能匹配 "foooood"中的所有 o。"o{1,}" 等價于 "o+"。"o{0,}" 則等價于 "o*"。
re{ n, m} 匹配 n 到 m 次由前面的正則表達(dá)式定義的片段,貪婪方式
a| b 匹配a或b
(re) 匹配括號內(nèi)的表達(dá)式,也表示一個組
(?imx) 正則表達(dá)式包含三種可選標(biāo)志:i, m, 或 x 。只影響括號中的區(qū)域。
(?-imx) 正則表達(dá)式關(guān)閉 i, m, 或 x 可選標(biāo)志。只影響括號中的區(qū)域。
(?: re) 類似 (...), 但是不表示一個組
(?imx: re) 在括號中使用i, m, 或 x 可選標(biāo)志
(?-imx: re) 在括號中不使用i, m, 或 x 可選標(biāo)志
(?#...) 注釋.
(?= re) 前向肯定界定符。如果所含正則表達(dá)式,以 ... 表示,在當(dāng)前位置成功匹配時成功,否則失敗。但一旦所含表達(dá)式已經(jīng)嘗試,匹配引擎根本沒有提高;模式的剩余部分還要嘗試界定符的右邊。
(?! re) 前向否定界定符。與肯定界定符相反;當(dāng)所含表達(dá)式不能在字符串當(dāng)前位置匹配時成功
(?> re) 匹配的獨(dú)立模式,省去回溯。
\w 匹配字母數(shù)字及下劃線
\W 匹配非字母數(shù)字及下劃線
\s 匹配任意空白字符,等價于 [\t\n\r\f].
\S 匹配任意非空字符
\d 匹配任意數(shù)字,等價于 [0-9].
\D 匹配任意非數(shù)字
\A 匹配字符串開始
\Z 匹配字符串結(jié)束,如果是存在換行,只匹配到換行前的結(jié)束字符串。
\z 匹配字符串結(jié)束
\G 匹配最后匹配完成的位置。
\b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\n, \t, 等. 匹配一個換行符。匹配一個制表符。等
\1...\9 匹配第n個分組的內(nèi)容。
\10 匹配第n個分組的內(nèi)容,如果它經(jīng)匹配。否則指的是八進(jìn)制字符碼的表達(dá)式。

RE模塊

re.match()函數(shù)

re.math()函數(shù)嘗試從字符串的起始位置匹配一個模式,語法格式如下:

re.match(pattern,string,flag=0)

函數(shù)參數(shù)說明:pattern指匹配的正則表達(dá)式;string要匹配的字符串;flag為標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如是否區(qū)分大小寫,多行匹配等。

如果匹配成功,re.match()方法就返回一個匹配的對象,否則返回None。

正則表達(dá)式對象

re.RegexObject

re.compile() 返回 RegexObject 對象。

re.MatchObject

group() 返回被 RE 匹配的字符串。

  • start() 返回匹配開始的位置
  • end() 返回匹配結(jié)束的位置
  • span() 返回一個元組包含匹配 (開始,結(jié)束) 的位置

示例如下:

#! /usr/bin/python3
# -*- coding:UTF-8 -*-
import re
#re.match()只匹配字符串開始的字符,如果開始的字符串不符合正則表達(dá)式,就返回None
print('re.match(\'hello\',\'hello world\') = ',re.match('hello','hello world'))
#span()函數(shù)返回一個元組,表示匹配的區(qū)間,左閉又開
#起始位置匹配
print('re.match(\'hello\',\'hello world\').span() = ',re.match('hello','hello world').span())
#非起始位置匹配
print('re.match(\'world\',\'hello world\') = ',re.match('world','hello world'))

輸出:

re.match('hello','hello world') =  <_sre.SRE_Match object; span=(0, 5), match='hello'>
re.match('hello','hello world').span() =  (0, 5)
re.match('world','hello world') =  None
正則表達(dá)式修飾符 - 可選標(biāo)志

正則表達(dá)式可以包含一些可選標(biāo)志修飾符來控制匹配的模式。修飾符被指定為一個可選的標(biāo)志。多個標(biāo)志可以通過按位 OR(|) 它們來指定。如 re.I | re.M 被設(shè)置成 I 和 M 標(biāo)志,re.M|re.I:這兩參數(shù)表示多行匹配|不區(qū)分大小寫,同時生效。

修飾符 描述
re.I 使匹配對大小寫不敏感
re.L 做本地化識別(locale-aware)匹配
re.M 多行匹配,影響 ^ 和 $
re.S 使 . 匹配包括換行在內(nèi)的所有字符
re.U 根據(jù)Unicode字符集解析字符。這個標(biāo)志影響 \w, \W, \b, \B.
re.X 該標(biāo)志通過給予你更靈活的格式以便你將正則表達(dá)式寫得更易于理解。
匹配對象方法
匹配對象方法 描述
group(num=0) 匹配的整個表達(dá)式的字符串,group() 可以一次輸入多個組號,在這種情況下它將返回一個包含那些組所對應(yīng)值的元組。編號0代表整個匹配的字符串,不填寫參數(shù)時,返回group(0);沒有匹配項(xiàng)時,返回None;多次匹配成功后,返回最后一次匹配成功的字符串。
groups() 返回一個包含所有小組字符串的元組,從 1 到 所含的小組號。

re.search()方法

re.search()方法用于掃描整個字符串,并返回第一個成功匹配的字符。語法格式如下:

re.search(pattern,string,flag=0)

函數(shù)參數(shù)說明:pattern指匹配的正則表達(dá)式;string要匹配的字符串;flag為標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如是否區(qū)分大小寫,多行匹配等。

如果匹配成功,re.match()方法就返回一個匹配的對象,否則返回None。示例如下:

#re.search(),匹配整個字符串,直到找到一個匹配的對象,匹配結(jié)束后沒有找到匹配值才返回None
#起始位置匹配
print('re.search(\'hello\',\'hello world\').span() = ',re.search('hello','hello world').span())
#非起始位置匹配
print('re.search(\'world\',\'hello world\').span() = ',re.search('world','hello world').span())

輸出:

re.search('hello','hello world').span() =  (0, 5)
re.search('world','hello world').span() =  (6, 11)

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

函數(shù)名 作用
re.match() 只匹配字符串開始的字符,如果開始的字符不符合正則表達(dá)式,就返回None
re.sarch() 匹配整個字符串,直到找到一個匹配的對象,匹配結(jié)束后仍不符合,才返回None

示例如下:

#RE模塊示例
line = 'cats are smarter than dogs'
matchobj = re.match(r'dogs',line,re.M|re.I)
if matchobj:
    print('使用match,匹配的字符串是:',matchobj.group())
else:
    print('沒有匹配項(xiàng)')
matchobj = re.search(r'dogs',line,re.M|re.I)
if matchobj:
    print('使用search,匹配的字符串是:',matchobj.group())
    print('第一個匹配的字符串是:',matchobj.group(0))
    #下面為什么是空?
    print('使用search,全部匹配的字符串是:',matchobj.groups())
    print('一共匹配了%s個元素' % len(matchobj.groups()))
    for matchstr in matchobj.groups():
        print('matchstr is ',matchstr)
else:
    print('沒有匹配項(xiàng)')

輸出:

沒有匹配項(xiàng)
使用search,匹配的字符串是: dogs
第一個匹配的字符串是: dogs
使用search,全部匹配的字符串是: ()
一共匹配了0個元素

貪婪模式和非貪婪模式

Python里數(shù)量詞默認(rèn)是貪婪的(在少數(shù)語言里也默認(rèn)非貪婪),總是嘗試匹配盡可能多的字符;非貪婪模式正好相反,總是嘗試匹配盡可能少的字符。

示例:

#貪婪模式
print(re.match(r'^(\d+)(0*)$','102300').groups())
#非貪婪模式
print(re.match(r'^(\d+?)(0*)$','102300').groups())
#貪婪模式,匹配盡可能多的字符
print(re.match(r'ab*','abbbbbc').span())
#非貪婪模式,匹配0到1個字符
print(re.match(r'ab*?','abbbbbc').span())

輸出:

('102300', '')
('1023', '00')
(0, 6)
(0, 1)

編譯

當(dāng)在Python中使用正則表達(dá)式時,re模塊會做以下兩下事情:

  • 編譯正則表達(dá)式,如果正則表達(dá)式的字符串本身不合法,就會報(bào)錯。
  • 用編譯后的正則表達(dá)式匹配字符串。

如果一個正則表達(dá)式需要出現(xiàn)很多次,處于效率的考慮,我們可以預(yù)編譯這個正則表達(dá)式。這樣重復(fù)使用時,就不會重復(fù)編譯的動作,直接匹配即可。示例如下:

telReg = re.compile(r'^(\d{3})-(\d{3,8})$')
print(telReg.match('010-1234567').groups())
def printTel(tels):
    i = 0
    for tel in telReg.match('010-1234567').groups():
        i += 1
        print('part%d of tel = %s' % (i, tel))
printTel(telReg.match('010-1234567').groups())
print(telReg.match('010-123').groups())

輸出:

('010', '1234567')
part1 of tel = 010
part2 of tel = 1234567
('010', '123')

檢索和替換

Python 的 re 模塊提供了re.sub用于替換字符串中的匹配項(xiàng)。

語法:

re.sub(pattern, repl, string, count=0, flags=0)

參數(shù):

  • pattern : 正則中的模式字符串。
  • repl : 替換的字符串,也可為一個函數(shù)。
  • string : 要被查找替換的原始字符串。
  • count : 模式匹配后替換的最大次數(shù),默認(rèn) 0 表示替換所有的匹配。

示例如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import re
 
phone = "2004-959-559 # 這是一個國外電話號碼"
 
# 刪除字符串中的 Python注釋 
num = re.sub(r'#.*$', "", phone)
print "電話號碼是: ", num
 
# 刪除非數(shù)字(-)的字符串 
num = re.sub(r'\D', "", phone)
print "電話號碼是 : ", num

以上實(shí)例執(zhí)行結(jié)果如下:

電話號碼是:  2004-959-559 
電話號碼是 :  2004959559

repl 參數(shù)是一個函數(shù)

以下實(shí)例中將字符串中的匹配的數(shù)字乘以 2:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import re
 
# 將匹配的數(shù)字乘以 2
def double(matched):
    value = int(matched.group('value'))
    return str(value * 2)
 
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))

執(zhí)行輸出結(jié)果為:

A46G8HFD1134
?著作權(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)容

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