1. 程式人生 > >網路爬蟲筆記【6】 Python 中的正則表示式模組與應用

網路爬蟲筆記【6】 Python 中的正則表示式模組與應用

python3 內建的 re 模組,包含了正則表示式的操作集。 re 模組的一般使用步驟如下:

  1. 編譯正則表示式,即使用 compile() 函式將正則表示式的字串形式編譯為一個 Pattern 物件。
  2. 對目標字串進行匹配,即通過 Pattern 物件提供的一些列方法對文字進行匹配查詢,獲得匹配結果(Match 物件)
  3. 提取結果資訊,即使用 Match 物件提供的屬性和方法獲得資訊,還可以根據需要進行其他操作。

compile 函式

Compile 函式用於編譯正則表示式,生成一個 Pattern 物件。一般使用形式如下:

import re
pattern = re.compile(一個正則表示式)

成功編譯並構造 pattern 物件後,就可以使用 pattern 物件方法查詢、替換、統計目標字串中與正則表示式匹配的子字串了。pattern 物件可呼叫的方法有:

  • match 方法:從起始位置開始查詢,一次匹配
  • search
  • fullmatch
  • sub
  • subn
  • split
  • purge
  • template
  • escape
  • error
  • findall
  • finditer 事實上,這些函式不僅是物件可呼叫的,也是可以使用 re 模組直接呼叫的。

match 方法

match 方法用於在字串起始位置進行模式匹配,若匹配則返回 Match 物件,否則返回 None。

match(pattern, string, flags=0) 
# method of re module Try to apply the pattern at the start of the string, returning a match object, or None if no match was found. 

match(string=None, pos=0, endpos=None, pattern=None) 
# method of Pattern instance Matches zero or more characters at the beginning of the string.

下面舉例說明:

''' re 模組 compile 方法與 match 方法示例'''
import re

text1 = 'sdaksfhksjdfnkfsjldhfsk234sfd65s1df55s3sdf4156sd4et489t74t6'
text2 = 'SDakufasdakru9013rgp2k;.,/,.;.t2,445,3/4l,63;lk,3;l,43'

print('執行結果:\n')
pattern = re.compile('sdak')

# <_sre.SRE_Match object; span=(0, 4), match='sdak'>
match = pattern.match(text1)
print(match)
print('---'*10)

# None
match = pattern.match(text2)
print(match)
print('---'*10)

# <_sre.SRE_Match object; span=(7, 11), match='sdak'>
match = pattern.match(text2, pos = 7)
print(match)

if match:
    # sdak
    print(match.group())
print('---'*10)

# re.IGNORECASE 忽略大小寫
pattern = re.compile('sdak', flags = re.IGNORECASE)
match = pattern.match(text2)

if match:
    # SDak
    print(match.group())
print('---'*10)
執行結果:

<_sre.SRE_Match object; span=(0, 4), match='sdak'>
------------------------------
None
------------------------------
<_sre.SRE_Match object; span=(7, 11), match='sdak'>
sdak
------------------------------
SDak
------------------------------

Match 物件

match 物件是正則表示式匹配目標字串後返回的結果物件。它可呼叫以下方法:

  • group([group1, …])方法,用於獲得一個或多個分組匹配的字串,當要獲得整個匹配的子串時,可直接使用 group() 或 group(0);
  • start([group]) 方法用於獲取分組匹配的子串在整個字串中的起始位置(子串第一個字元的索引),引數預設值為 0;
  • end([group]) 方法用於獲取分組匹配的子串在整個字串中的結束位置(子串最後一個字元的索引+1),引數預設值為 0;
  • span([group]) 方法返回 (start(group), end(group))。
import re

text = '[email protected]中文QQ郵箱'

# 定義正則表示式,匹配目標字串中的電子郵箱
regexstr = '\[email protected]\w+\.[a-z]+'

# 將正則表示式編譯成 Pattern 物件
pattern = re.compile(regexstr)

# 匹配
match = pattern.match(text)

if match:
    print(match.group())
    print(match.start())
    print(match.end())
    print(match.span())
執行結果:

[email protected]
0
15
(0, 15)

search 方法

Search 方法用於查詢字串的任何位置,它只返回從左到右第一個匹配的結果,而不是查詢所有匹配的結果。

# search 方法示例

import re

text = 'one12twothree34four'

# 設定正則表示式查詢第一個數字串
regexstr = '\d+'
pattern = re.compile(regexstr)

# match 方法是從第一個字元開始匹配,這裡第一個字元不是數字,則返回 None
match = pattern.match(text)

print('pattern.match:')
print(match)
    
print('---'*10)
# search 方法是從左往右檢索,返回第一個匹配到的結果,這裡返回 12
match = pattern.search(text)
print('pattern.search:')

if match:
    print(match.group())
    print(match.span())
執行結果:

pattern.match:
None
------------------------------
pattern.search:
12
(3, 5)

findall 與 finditer 方法

上面的 match 和 search 方法都是一次性匹配,而有時需要獲取目標字串中所有匹配的結果,這需要使用 findall 或 finditer 方法。使用形式如下:

findall(string[, pos[, endpos]])
其中,string 是待匹配的字串,pos 和 endpos 是可選引數,指定字串的起始和終點位置,預設值分別是 0 和 len (字串長度)。

finditer 方法的行為跟 findall 的行為類似,也是搜尋整個字串,獲得所有匹配的結果,但是它返回一個順序訪問每一個匹配結果(Match 物件)的迭代器。

簡單講就是,findall 會把所有結果一次性返回,finditer 得用迴圈一個一個返回

import re

text = '你好[email protected]中文QQ郵箱'

# 定義正則表示式,匹配字串中的中文
regexstr = u'[\u4e00-\u9fa5]+'

pattern = re.compile(regexstr)
matchlist = pattern.findall(text)

if matchlist:
    print(matchlist)
    
else:
    print('None')

print('---'*10)

matchiter = pattern.finditer(text)
if matchiter:
    print(matchiter)
    for m in matchiter:
        print('Match result:{}, postion: {}'.format(m.group(),m.span()))
else:
    print('None')
執行結果:

['你好', '中文', '郵箱']
------------------------------
<callable_iterator object at 0x00000165B601D630>
Match result:你好, postion: (0, 2)
Match result:中文, postion: (17, 19)
Match result:郵箱, postion: (21, 23)

split 方法

split 方法按照能夠匹配的子串將字串分割後返回列表,它的使用形式如下:

split(string[, maxsplit])
其中,maxsplit 用於指定最大分割次數,不指定將全部分割。
import re

text = 'a,b;;c d  ,;e'
# 正則表示式,字串前加 r,表示該字串是 raw string。
regexstr = r'[\,\;\s]+'

pattern = re.compile(regexstr)
match = pattern.split(text)

if match:
    print(match)
else:
    print('None')
執行結果:

['a', 'b', 'c', 'd', 'e']

sub 方法

sub 方法用於替換。它的使用形式如下:

sub(repl, string[, count])
  • repl 可以是字串也可以是一個函式
    • 如果 repl 是字串,則會使用 repl 去替換字串每一個匹配的子串,並返回替換後的字串,另外,repl 還可以使用 id 的形式來引用分組,但不能使用編號 0;
    • 如果 repl 是函式,這個方法應當只接受一個引數(Match物件),並返回一個字串用於替換(返回的字串中不能再引用分組)。
  • count 用於指定最多替換次數,不指定時全部替換。
import re

# 設定模式:兩個英文字元或數字的分組,中間用空格隔開
text = 'Hello 123, Hello 456'
regexstr = r'(\w+) (\w+)'
repl = 'Hello World'
pattern = re.compile(regexstr)

# 使用 'Hello World' 替換 'Hello 123' 和 'Hello 456'
res = pattern.sub(repl,text)
print(res)
print('---'*10)

# 引用分組
repl = r'\2 \1'
# regexstr 第一個括號裡匹配到的是 \1 ,第二個括號裡匹配到的是 \2
res = pattern.sub(repl,text)
print(res)
print('---'*10)

# 指定替換次數
def func(m):
    return ('hi' + ' ' + m.group(2))

print(pattern.sub(func,text))
print(pattern.sub(func,text,1))
執行結果:

Hello World, Hello World
------------------------------
123 Hello, 456 Hello
------------------------------
hi 123, hi 456
hi 123, Hello 456

貪婪模式與非貪婪模式

  • 貪婪模式,指的是整個表示式匹配成功的前提下,儘可能多的匹配(使用 * ),python 裡數量詞預設是貪婪的;
  • 非貪婪模式,指的是整個表示式匹配成功的前提下,儘可能少的匹配(使用 *? )
# demo 1

import re

text = 'abbbbbbbbbbbbccccc'
regexStr1 = 'ab*'
regexStr2 = 'ab*?'

pattern = re.compile(regexStr1)
match = pattern.match(text)
print('貪婪模式:' + match.group())

print('---'*10)

pattern = re.compile(regexStr2)
match = pattern.match(text)
print('非貪婪模式:' + match.group())
執行結果:

貪婪模式:abbbbbbbbbbbb
------------------------------
非貪婪模式:a
# demo 2

import re

text = 'aa<div>test1</div>bb<div>test2</div>cc'
regexStr1 = '<div>.*</div>'
regexStr2 = '<div>.*?</div>'

pattern = re.compile(regexStr1)
m = pattern.search(text)
print(m.group())

print('---'*10)

pattern = re.compile(regexStr2)
m = pattern.search(text)
print(m.group())
執行結果:

<div>test1</div>bb<div>test2</div>
------------------------------
<div>test1</div>