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