Python re模塊與正則表達式詳解

Python 中使用re模塊處理正則表達式,正則表達式主要用來處理文本中的查找,匹配,替換,分割等問題;我們先來看一個問題,切入正則表達式。

問題:

匹配字符串,最少以3個數字開頭。使用Python代碼如何實現?
檢查條件:

1>字符串長度判斷;
2>判斷前三個字符是否是數字;

這樣實現起來有點囉嗦,我們可以使用正則表達式,先來看正則表達式基本語法。

1 正則表達式基本語法

.           匹配任意字符(不包括換行符)
^           匹配開始位置,多行模式下匹配每一行的開始
$           匹配結束位置,多行模式下匹配每一行的結束
*            匹配前一個元字符0到多次
+            匹配前一個元字符1到多次
?           匹配前一個元字符0到1次
{m,n}       匹配前一個元字符m到n次
\           轉義字符,例如\.只能匹配.
[]          字符集,一個字符的集合,可匹配其中任意一個字符
\d          匹配一個數字, 相當於 [0-9]
\D          匹配非數字,相當於 [^0-9]
\s          匹配任意空白字符, 相當於 [ \t\n\r\f\v]
\S          匹配非空白字符,相當於 [^ \t\n\r\f\v]
\w          匹配數字、字母、下劃線中任意一個字符, 相當於 [a-zA-Z0-9_]
\W          匹配非數字、字母、下劃線中的任意字符,相當於 [^a-zA-Z0-9_]
|           邏輯表達式 或 ,比如 a|b 代表可匹配 a 或者 b
(...)       分組

給一坨這個玩意,怎麼用,都需要記住嗎?
如果能記住就記住,如果很久不使用,就忘記吧;
等使用的時候直接查資料,理解能使用即可。
下面我們結合re模塊,看正則表達式如何使用。

2 re.compile方法;

Python中正則表達式執行過程:根據表達式編譯生成Pattern對象,然後進行相關處理;
如果高頻率使用一個固定的正則表達式,我們可以提前生成Pattern對象,提高效率。

compile方法:

import re
re.compile(pattern, flags=0) #pattern爲正則表達式

參數:
pattern:正則表達式,是指爲字符串;爲了防止轉義推薦使用原字符串(r'xxx');
flags:編譯標誌位,修改正則表達式的匹配方式,例如:大小寫區分,換行處理等;

例子:匹配任意一個數字開頭字符串:

import re
pobj = re.compile(r'\d')
type(pobj)

輸出結果:re.Pattern對象;
問題:如何來匹配呢?

3 re.match方法

re.match方法:從起始位置開始匹配,返回None或者re.Match對象;

#re模塊match方法,參數:pattern:正則表達式,string:處理字符串
re.match(pattern, string, flags=0)
#re.Pattern對象中match方法,參數:string:處理字符串
re.Pattern.match(string, pos=0, endpos=...)

練習:匹配一個數字開頭字符串:

import re
ma = re.match(r'\d', '123')
print(ma)

輸出結果:

<re.Match object; span=(0, 1), match='1'>

match方法匹配過程:生成Pattern對象,然後進行匹配;
如何獲取匹配結果?來看Match對象相關方法。

方法 說明
ma.end(group=0, /) 返回指定分組的結束位置
ma.start(group=0, /) 返回指定分組的開始位置
ma.span(group=0, /) 返回指定分組開始與結束位置
ma.group([group1, ...]) 返回字符串或者元組
ma.groups(default=None) 返回所有分組信息
groupdict([default=None]) 根據key獲取分組信息

實際操作下,理解起來就容易了:

import re
import re
#正則表達式:匹配內容:數字+a~z+數字,並且進行分組
ma = re.match(r'(\d)\w*(\d)', '1c3')
#匹配結果:'1c3'
print('group():', ma.group())
#獲取指定分組:1
print('group(1):', ma.group(1)) 
#獲取多個分組:('1', '3')
print('group(1,2):', ma.group(1,2))
#獲取所有分組:('1', '3')
print('groups():', ma.groups())
#獲取匹配結果索引:(0, 3)
print('span():', ma.span())
#獲取指定分組索引:(0, 1)
print('span(1):',ma.span(1))

輸出結果:

group(): 1c3
group(1): 1
group(1,2): ('1', '3')
groups(): ('1', '3')
span(): (0, 3)
span(1): (0, 1)

match方法只能用於從頭匹配,如何在整個字符串中查找?
使用search方法。

4:re.search方法

search方法用於在字符串中查找,返回Match對象或者None;

search(pattern, string, flags=0);參數與match類似。

練習:查找第一次出現的數字組成的字串,例如:
在字符串:'pay:2000 date:2019-03-04',找到支付價格:2000;
分析:

1>支付前固定值:'pay:'
2>支付金額:數字字符串

對應正則表達式邏輯:'pay:'+匹配數字直到非數字字符;具體實現:

s = 'pay:2000 date:2019-03-04'
#\d+:匹配數字一次或者多次
ma = re.search(r'pay:\d+', s)
print(ma)

輸出結果:

<re.Match object; span=(0, 8), match='pay:2000'>

如何獲取2000這個值?增加一個分組,代碼實現:

s = 'pay:2000 date:2019-03-04'
#\d+:匹配數字一次或者多次,使用分組
ma = re.search(r'pay:(\d+)', s)
print(ma)
#獲取分組1對應值
print(ma.group(1))

輸出結果:

<re.Match object; span=(0, 8), match='pay:2000'>
2000

5 re.findall/finditer方法

re.findall:在字符串中根據正則表達式查找所有匹配,返回查找結果組成列表;
re.finditer與findall功能相同,返回自迭代器;

re.findall(pattern, string, flags=0) 

練習:查找字符串中所有數字字符串,
例如:'pay:2000 date:2019-03-04' 查找數字結果:['2000', '2019', '03', '04']
實現如下:

import re
s = 'pay:2000 date:2019-03-04'
result = re.findall(r'\d+', s)
print(result)

結果爲列表:['2000', '2019', '03', '04'];

6 re.split方法

re.split:字符串中根據正則表達式查找匹配字符串,然後進行切分,返回字串列表;

re.split(pattern, string, maxsplit=0, flags=0)
#maxsplit:切分次數,默認所有匹配都切分

練習:

info = 'system:linux,  cpu:x64  memory 8G'
整理格式:
dinfo = {'system':'linux', 'cpu':'x64', 'memory':'8G'}

分析:

1>對info使用非字母,數字進行切分;
2>切分後將其整理成字典;

第一步切分:

info = 'system:linux, cpu:x64 memory 8G'
#正則表達式:\W+,匹配1個或多個
s = re.split(r'\W+',info)
print(s)

切分結果:['system', 'linux', 'cpu', 'x64', 'memory', '8G'];
第二步整理字典:

info = 'system:linux, cpu:x64 memory 8G'
s = re.split(r'\W+',info)
dinfo = {}
for index in range(0, len(s), 2):
    dinfo[s[index]] = s[index+1]
print(dinfo)

輸出結果:{'system': 'linux', 'cpu': 'x64', 'memory': '8G'}

7 re.sub與re.subn

re.sub與re.subn實現的字符串替換功能;

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

re.sub方法根據正則表達式將匹配子串替換成設置值並返回新字符串;參數如下:

主要參數 說明
pattern 正則表達式
repl 替換內容,可以是字符串或者函數
string 處理字符串
count 替換數量

re.subn與re.sub類似,返回替換數量與新字符串;

練習:

s  = "user:sun,pwd:222222",將密碼:222222 替換爲:******;

可以直接使用字符串替換方法:

s.replace('222222', '******')
#結果:'user:sun,pwd:******'

如果密碼爲不一樣數字如何替換?例如:

s  = "user:sun,pwd:234567"

使用re.sub方法:

#將pwd:xxxx替換成******
re.sub(r'pwd:(\d+)', "******", s)
#結果:'user:sun,******'

問題:pwd:去哪裏了?如何處理?使用分組。

#pattern使用兩個分組
#repl爲原字符串,\1代表第一個分組內容,
re.sub(r'(pwd:)(\d+)', r"\1******", s)

替換結果:

'user:sun,pwd:******'

大家可以理解下這個題目。

新的問題來了,一組考試成績:

s = 'math:90, chinese:90, english:50'

大於等於60,替換成Pass,否則替換成Faild;推薦使用正則。

我們可以使用函數功能,先來看匹配分數,將其替換爲空字符串;

re.sub(r'\d+', '', s)

結果:'math:, chinese:, english:';
我們將repl替換成函數,函數有一個參數,返回值爲空字符串;

def func(arg):
    print(arg)
    return ''
re.sub(r'\d+', func, s)

輸出結果:

<_sre.SRE_Match object; span=(5, 7), match='90'>
<_sre.SRE_Match object; span=(17, 19), match='90'>
<_sre.SRE_Match object; span=(29, 31), match='50'>
'math:, chinese:, english:'

可以看到func中參數爲每個匹配的match對象,我們可以獲取這個值,並對其處理。

def func(arg):
    #獲取分數
    score = int(arg.group())
    #重置返回結果
    if score <60:
        return 'Faild'
    return 'Pass'
re.sub(r'\d+', func, s)

輸出結果:

'math:Pass, chinese:Pass, english:Faild'

8 flags標誌位:

match,split等方法中都有一個標誌位,主要設置值如下:

flag值 說明
re.I/re.IGNORECASE 匹配不區分大小寫
re.L/re.LOCALE \w, \W, \b, \B, \s and \S 依賴於本地
re.M/re.MULTILINE 多行匹配,對'^'與'$'有影響
re.S/re.DOTALL 使'.'特殊字符匹配任何字符
re.U/re.UNICODE 根據Unicode字符集解析字符。\w, \W, \b, \B, \d, \D, \s和 \S 取決於UNICODE定義的字符屬性
re.X/re.VERBOSE 此標誌允許您編寫正則表達式,可添加註釋

這些標誌位可以結合使用,例如:re.M | re.S。
每個標誌使用案例與對比如下:

re.I:匹配忽略大小寫

ma = re.match(r'name:\w+', 'Name:sun age:10')
print(ma)
#添加re.I標誌
ma = re.match(r'name:\w+', 'Name:sun age:10', re.I)
print(ma)

結果:

None
<re.Match object; span=(0, 8), match='Name:sun'>

re.M:多行匹配

找到字符串中與戶名

#注意,中間的換行\n
s = 'Name:sun age:10\nname:liu, age:9'
#正則表達式:每行開頭開始匹配,默認處理第一行
result = re.findall(r'^name:\w+', s, re.I)
print(result)

輸出結果:['Name:sun'];我們想要找到所有用戶名?添加re.M,代碼如下:

s = 'Name:sun age:10\nname:liu, age:9'
#re.I | re.M,支持設置多個標誌位
result = re.findall(r'^name:\w+', s, re.I|re.M)
print(result)

結果:['Name:sun', 'name:liu']

re.S 修改'.'的行爲

字符串:

what = 'I Say:"No!\nNo!"'

找出我說的話:"No!\nNo!"
匹配規則,雙引號中間字符串,實現:

what = 'I Say:"No!\nNo!"'
ma = re.search(r'\".+\"', what)
print(ma)

輸出結果:None;因爲'.'不能匹配'\n',設置標誌re.S,實現:

what = 'I Say:"No!\nNo!"'
ma = re.search(r'\".+\"', what, re.S)
print(ma)

輸出結果:

<re.Match object; span=(6, 15), match='"No!\nNo!"'>

以上這些就是re模塊常用使用方法及正則表達式基本語法,後面文章我們在介紹正則表達式更高級使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章