Python 正則表達式 re 模塊簡明筆記

簡介

正則表達式(regular expression)是能夠匹配文本片斷的模式。最簡單的正則表達式就是普通字符串,能夠匹配其自身。好比,正則表達式 'hello' 能夠匹配字符串 'hello'。javascript

要注意的是,正則表達式並非一個程序,而是用於處理字符串的一種模式,若是你想用它來處理字符串,就必須使用支持正則表達式的工具,好比 Linux 中的 awk, sed, grep,或者編程語言 Perl, Python, Java 等等。html

正則表達式有多種不一樣的風格,下表列出了適用於 Python 或 Perl 等編程語言的部分元字符以及說明:java

re 模塊

在 Python 中,咱們可使用內置的 re 模塊來使用正則表達式。python

有一點須要特別注意的是,正則表達式使用 \ 對特殊字符進行轉義,好比,爲了匹配字符串 'python.org',咱們須要使用正則表達式 'python\.org',而 Python 的字符串自己也用 \ 轉義,因此上面的正則表達式在 Python 中應該寫成 'python\\.org',這會很容易陷入 \ 的困擾中,所以,咱們建議使用 Python 的原始字符串,只需加一個 r 前綴,上面的正則表達式能夠寫成:正則表達式

r'python\.org'複製代碼

re 模塊提供了很多有用的函數,用以匹配字符串,好比:express

  • compile 函數
  • match 函數
  • search 函數
  • findall 函數
  • finditer 函數
  • split 函數
  • sub 函數
  • subn 函數

re 模塊的通常使用步驟以下:編程

  • 使用 compile 函數將正則表達式的字符串形式編譯爲一個 Pattern 對象
  • 經過 Pattern 對象提供的一系列方法對文本進行匹配查找,得到匹配結果(一個 Match 對象)
  • 最後使用 Match 對象提供的屬性和方法得到信息,根據須要進行其餘的操做

compile 函數

compile 函數用於編譯正則表達式,生成一個 Pattern 對象,它的通常使用形式以下:編程語言

re.compile(pattern[, flag])複製代碼

其中,pattern 是一個字符串形式的正則表達式,flag 是一個可選參數,表示匹配模式,好比忽略大小寫,多行模式等。ide

下面,讓咱們看看例子。函數

import re

# 將正則表達式編譯成 Pattern 對象 
pattern = re.compile(r'\d+')複製代碼

在上面,咱們已將一個正則表達式編譯成 Pattern 對象,接下來,咱們就能夠利用 pattern 的一系列方法對文本進行匹配查找了。Pattern 對象的一些經常使用方法主要有:

  • match 方法
  • search 方法
  • findall 方法
  • finditer 方法
  • split 方法
  • sub 方法
  • subn 方法

match 方法

match 方法用於查找字符串的頭部(也能夠指定起始位置),它是一次匹配,只要找到了一個匹配的結果就返回,而不是查找全部匹配的結果。它的通常使用形式以下:

match(string[, pos[, endpos]])複製代碼

其中,string 是待匹配的字符串,pos 和 endpos 是可選參數,指定字符串的起始和終點位置,默認值分別是 0 和 len (字符串長度)。所以,當你不指定 pos 和 endpos 時,match 方法默認匹配字符串的頭部

當匹配成功時,返回一個 Match 對象,若是沒有匹配上,則返回 None。

看看例子。

>>> import re
>>> pattern = re.compile(r'\d+')                    # 用於匹配至少一個數字
>>> m = pattern.match('one12twothree34four')        # 查找頭部,沒有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 2, 10) # 從'e'的位置開始匹配,沒有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 3, 10) # 從'1'的位置開始匹配,正好匹配
>>> print m                                         # 返回一個 Match 對象
<_sre.SRE_Match object at 0x10a42aac0>
>>> m.group(0)   # 可省略 0
'12'
>>> m.start(0)   # 可省略 0
3
>>> m.end(0)     # 可省略 0
5
>>> m.span(0)    # 可省略 0
(3, 5)複製代碼

在上面,當匹配成功時返回一個 Match 對象,其中:

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

再看看一個例子:

>>> import re
>>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)   # re.I 表示忽略大小寫
>>> m = pattern.match('Hello World Wide Web')
>>> print m                               # 匹配成功,返回一個 Match 對象
<_sre.SRE_Match object at 0x10bea83e8>
>>> m.group(0)                            # 返回匹配成功的整個子串
'Hello World'
>>> m.span(0)                             # 返回匹配成功的整個子串的索引
(0, 11)
>>> m.group(1)                            # 返回第一個分組匹配成功的子串
'Hello'
>>> m.span(1)                             # 返回第一個分組匹配成功的子串的索引
(0, 5)
>>> m.group(2)                            # 返回第二個分組匹配成功的子串
'World'
>>> m.span(2)                             # 返回第二個分組匹配成功的子串
(6, 11)
>>> m.groups()                            # 等價於 (m.group(1), m.group(2), ...)
('Hello', 'World')
>>> m.group(3)                            # 不存在第三個分組
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: no such group複製代碼

search 方法

search 方法用於查找字符串的任何位置,它也是一次匹配,只要找到了一個匹配的結果就返回,而不是查找全部匹配的結果,它的通常使用形式以下:

search(string[, pos[, endpos]])複製代碼

其中,string 是待匹配的字符串,pos 和 endpos 是可選參數,指定字符串的起始和終點位置,默認值分別是 0 和 len (字符串長度)。

當匹配成功時,返回一個 Match 對象,若是沒有匹配上,則返回 None。

讓咱們看看例子:

>>> import re
>>> pattern = re.compile('\d+')
>>> m = pattern.search('one12twothree34four')  # 這裏若是使用 match 方法則不匹配
>>> m
<_sre.SRE_Match object at 0x10cc03ac0>
>>> m.group()
'12'
>>> m = pattern.search('one12twothree34four', 10, 30)  # 指定字符串區間
>>> m
<_sre.SRE_Match object at 0x10cc03b28>
>>> m.group()
'34'
>>> m.span()
(13, 15)複製代碼

再來看一個例子:

# -*- coding: utf-8 -*-

import re

# 將正則表達式編譯成 Pattern 對象
pattern = re.compile(r'\d+') 

# 使用 search() 查找匹配的子串,不存在匹配的子串時將返回 None 
# 這裏使用 match() 沒法成功匹配 
m = pattern.search('hello 123456 789') 

if m: 
    # 使用 Match 得到分組信息 
    print 'matching string:',m.group()
    print 'position:',m.span()複製代碼

執行結果:

matching string: 123456
position: (6, 12)複製代碼

findall 方法

上面的 match 和 search 方法都是一次匹配,只要找到了一個匹配的結果就返回。然而,在大多數時候,咱們須要搜索整個字符串,得到全部匹配的結果。

findall 方法的使用形式以下:

findall(string[, pos[, endpos]])複製代碼

其中,string 是待匹配的字符串,pos 和 endpos 是可選參數,指定字符串的起始和終點位置,默認值分別是 0 和 len (字符串長度)。

findall 以列表形式返回所有能匹配的子串,若是沒有匹配,則返回一個空列表。

看看例子:

import re

pattern = re.compile(r'\d+')   # 查找數字
result1 = pattern.findall('hello 123456 789')
result2 = pattern.findall('one1two2three3four4', 0, 10)

print result1
print result2複製代碼

執行結果:

['123456', '789']
['1', '2']複製代碼

finditer 方法

finditer 方法的行爲跟 findall 的行爲相似,也是搜索整個字符串,得到全部匹配的結果。但它返回一個順序訪問每個匹配結果(Match 對象)的迭代器。

看看例子:

# -*- coding: utf-8 -*-

import re

pattern = re.compile(r'\d+')

result_iter1 = pattern.finditer('hello 123456 789')
result_iter2 = pattern.finditer('one1two2three3four4', 0, 10)

print type(result_iter1)
print type(result_iter2)

print 'result1...'
for m1 in result_iter1:   # m1 是 Match 對象
    print 'matching string: {}, position: {}'.format(m1.group(), m1.span())

print 'result2...'
for m2 in result_iter2:
    print 'matching string: {}, position: {}'.format(m2.group(), m2.span())複製代碼

執行結果:

<type 'callable-iterator'>
<type 'callable-iterator'> result1... matching string: 123456, position: (6, 12) matching string: 789, position: (13, 16) result2... matching string: 1, position: (3, 4) matching string: 2, position: (7, 8)複製代碼

split 方法

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

split(string[, maxsplit])複製代碼

其中,maxsplit 用於指定最大分割次數,不指定將所有分割。

看看例子:

import re

p = re.compile(r'[\s\,\;]+')
print p.split('a,b;; c d')複製代碼

執行結果:

['a', 'b', 'c', 'd']複製代碼

sub 方法

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

sub(repl, string[, count])複製代碼

其中,repl 能夠是字符串也能夠是一個函數:

  • 若是 repl 是字符串,則會使用 repl 去替換字符串每個匹配的子串,並返回替換後的字符串,另外,repl 還可使用 \id 的形式來引用分組,但不能使用編號 0;
  • 若是 repl 是函數,這個方法應當只接受一個參數(Match 對象),並返回一個字符串用於替換(返回的字符串中不能再引用分組)。

count 用於指定最多替換次數,不指定時所有替換。

看看例子:

import re

p = re.compile(r'(\w+) (\w+)')
s = 'hello 123, hello 456'

def func(m):
    return 'hi' + ' ' + m.group(2)

print p.sub(r'hello world', s)  # 使用 'hello world' 替換 'hello 123' 和 'hello 456'
print p.sub(r'\2 \1', s)        # 引用分組
print p.sub(func, s)
print p.sub(func, s, 1)         # 最多替換一次複製代碼

執行結果:

hello world, hello world
123 hello, 456 hello
hi 123, hi 456
hi 123, hello 456複製代碼

subn 方法

subn 方法跟 sub 方法的行爲相似,也用於替換。它的使用形式以下:

subn(repl, string[, count])複製代碼

它返回一個元組:

(sub(repl, string[, count]), 替換次數)複製代碼

元組有兩個元素,第一個元素是使用 sub 方法的結果,第二個元素返回原字符串被替換的次數。

看看例子:

import re

p = re.compile(r'(\w+) (\w+)')
s = 'hello 123, hello 456'

def func(m):
    return 'hi' + ' ' + m.group(2)

print p.subn(r'hello world', s)
print p.subn(r'\2 \1', s)
print p.subn(func, s)
print p.subn(func, s, 1)複製代碼

執行結果:

('hello world, hello world', 2)
('123 hello, 456 hello', 2)
('hi 123, hi 456', 2)
('hi 123, hello 456', 1)複製代碼

其餘函數

事實上,使用 compile 函數生成的 Pattern 對象的一系列方法跟 re 模塊的多數函數是對應的,但在使用上有細微差異。

match 函數

match 函數的使用形式以下:

re.match(pattern, string[, flags]):複製代碼

其中,pattern 是正則表達式的字符串形式,好比 \d+, [a-z]+

而 Pattern 對象的 match 方法使用形式是:

match(string[, pos[, endpos]])複製代碼

能夠看到,match 函數不能指定字符串的區間,它只能搜索頭部,看看例子:

import re

m1 = re.match(r'\d+', 'One12twothree34four')
if m1:
    print 'matching string:',m1.group()
else:
    print 'm1 is:',m1

m2 = re.match(r'\d+', '12twothree34four')
if m2:
    print 'matching string:', m2.group()
else:
    print 'm2 is:',m2複製代碼

執行結果:

m1 is: None
matching string: 12複製代碼

search 函數

search 函數的使用形式以下:

re.search(pattern, string[, flags])複製代碼

search 函數不能指定字符串的搜索區間,用法跟 Pattern 對象的 search 方法相似。

findall 函數

findall 函數的使用形式以下:

re.findall(pattern, string[, flags])複製代碼

findall 函數不能指定字符串的搜索區間,用法跟 Pattern 對象的 findall 方法相似。

看看例子:

import re

print re.findall(r'\d+', 'hello 12345 789')

# 輸出
['12345', '789']複製代碼

finditer 函數

finditer 函數的使用方法跟 Pattern 的 finditer 方法相似,形式以下:

re.finditer(pattern, string[, flags])複製代碼

split 函數

split 函數的使用形式以下:

re.split(pattern, string[, maxsplit])複製代碼

sub 函數

sub 函數的使用形式以下:

re.sub(pattern, repl, string[, count])複製代碼

subn 函數

subn 函數的使用形式以下:

re.subn(pattern, repl, string[, count])複製代碼

到底用哪一種方式

從上文能夠看到,使用 re 模塊有兩種方式:

  • 使用 re.compile 函數生成一個 Pattern 對象,而後使用 Pattern 對象的一系列方法對文本進行匹配查找;
  • 直接使用 re.match, re.search 和 re.findall 等函數直接對文本匹配查找;

下面,咱們用一個例子展現這兩種方法。

先看第 1 種用法:

import re

# 將正則表達式先編譯成 Pattern 對象
pattern = re.compile(r'\d+')

print pattern.match('123, 123')
print pattern.search('234, 234')
print pattern.findall('345, 345')複製代碼

再看第 2 種用法:

import re

print re.match(r'\d+', '123, 123')
print re.search(r'\d+', '234, 234')
print re.findall(r'\d+', '345, 345')複製代碼

若是一個正則表達式須要用到屢次(好比上面的 \d+),在多種場合常常須要被用到,出於效率的考慮,咱們應該預先編譯該正則表達式,生成一個 Pattern 對象,再使用該對象的一系列方法對須要匹配的文件進行匹配;而若是直接使用 re.match, re.search 等函數,每次傳入一個正則表達式,它都會被編譯一次,效率就會大打折扣。

所以,咱們推薦使用第 1 種用法。

匹配中文

在某些狀況下,咱們想匹配文本中的漢字,有一點須要注意的是,中文的 unicode 編碼範圍 主要在 [\u4e00-\u9fa5],這裏說主要是由於這個範圍並不完整,好比沒有包括全角(中文)標點,不過,在大部分狀況下,應該是夠用的。

假設如今想把字符串 title = u'你好,hello,世界' 中的中文提取出來,能夠這麼作:

# -*- coding: utf-8 -*-

import re

title = u'你好,hello,世界'
pattern = re.compile(ur'[\u4e00-\u9fa5]+')
result = pattern.findall(title)

print result複製代碼

注意到,咱們在正則表達式前面加上了兩個前綴 ur,其中 r 表示使用原始字符串,u 表示是 unicode 字符串。

執行結果:

[u'\u4f60\u597d', u'\u4e16\u754c']複製代碼

貪婪匹配

在 Python 中,正則匹配默認是貪婪匹配(在少數語言中多是非貪婪),也就是匹配儘量多的字符

好比,咱們想找出字符串中的全部 div 塊:

import re

content = 'aa<div>test1</div>bb<div>test2</div>cc'
pattern = re.compile(r'<div>.*</div>')
result = pattern.findall(content)

print result複製代碼

執行結果:

['<div>test1</div>bb<div>test2</div>']複製代碼

因爲正則匹配是貪婪匹配,也就是儘量多的匹配,所以,在成功匹配到第一個 </div> 時,它還會向右嘗試匹配,查看是否還有更長的能夠成功匹配的子串。

若是咱們想非貪婪匹配,能夠加一個 ?,以下:

import re

content = 'aa<div>test1</div>bb<div>test2</div>cc'
pattern = re.compile(r'<div>.*?</div>')    # 加上 ?
result = pattern.findall(content)

print result複製代碼

結果:

['<div>test1</div>', '<div>test2</div>']複製代碼

小結

  • re 模塊的通常使用步驟以下:
    • 使用 compile 函數將正則表達式的字符串形式編譯爲一個 Pattern 對象;
    • 經過 Pattern 對象提供的一系列方法對文本進行匹配查找,得到匹配結果(一個 Match 對象);
    • 最後使用 Match 對象提供的屬性和方法得到信息,根據須要進行其餘的操做;
  • Python 的正則匹配默認是貪婪匹配。

本文由 funhacks 發表於我的博客,採用 Creative Commons BY-NC-ND 4.0(自由轉載-保持署名-非商用-禁止演繹)協議發佈。
非商業轉載請註明做者及出處。商業轉載請聯繫做者本人。
本文標題爲: funhacks.net/2016/12/27/…
本文連接爲: Python 正則表達式 re 模塊簡明筆記

參考資料

相關文章
相關標籤/搜索