當前位置:
首頁 > 知識 > Python 正則表達式

Python 正則表達式

點擊上方「

Python開發

」,選擇「置頂公眾號」


關鍵時刻,第一時間送達!






簡介




正則表達式(regular expression)是可以匹配文本片段的模式。最簡單的正則表達式就是普通字元串,可以匹配其自身。比如,正則表達式 『hello』 可以匹配字元串 『hello』。




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




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






re 模塊




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




有一點需要特別注意的是,正則表達式使用 對特殊字元進行轉義,比如,為了匹配字元串 "python.org",我們需要使用正則表達式 "python.org",而 Python 的字元串本身也用 轉義,所以上面的正則表達式在 Python 中應該寫成 "python.org",這會很容易陷入 的困擾中,因此,我們建議使用 Python 的原始字元串,只需加一個 r 前綴,上面的正則表達式可以寫成:





r"python.org"



re 模塊提供了不少有用的函數,用以匹配字元串,比如:






  • compile 函數



  • match 函數



  • search 函數



  • findall 函數



  • finditer 函數



  • split 函數



  • sub 函數



  • subn 函數




re 模塊的一般使用步驟如下:






  • 使用 compile 函數將正則表達式的字元串形式編譯為一個 Pattern 對象



  • 通過 Pattern 對象提供的一系列方法對文本進行匹配查找,獲得匹配結果(一個 Match 對象)



  • 最後使用 Match 對象提供的屬性和方法獲得信息,根據需要進行其他的操作



  • compile 函數




compile 函數用於編譯正則表達式,生成一個 Pattern 對象,它的一般使用形式如下:




re.compile(pattern[, flag])




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




下面,讓我們看看例子。





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

" "

,

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

" "

,

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

"[一-龥]+"

)


result

=

pattern

.

findall

(

title

)


 


print

result




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




執行結果:





[u"你好", u"世界"]




貪婪匹配




在 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>"]




由於正則匹配是貪婪匹配,也就是儘可能多的匹配,因此,在成功匹配到第一個




時,它還會向右嘗試匹配,查看是否還有更長的可以成功匹配的子串。




如果我們想非貪婪匹配,可以加一個 ?,如下:





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 模塊的一般使用步驟如下:






  1. 使用 compile 函數將正則表達式的字元串形式編譯為一個 Pattern 對象;



  2. 通過 Pattern 對象提供的一系列方法對文本進行匹配查找,獲得匹配結果(一個 Match 對象);



  3. 最後使用 Match 對象提供的屬性和方法獲得信息,根據需要進行其他的操作;






  • Python 的正則匹配默認是貪婪匹配。




參考資料






  • 正則表達式 – 維基百科



  • Python正則表達式指南






  • 來源:geekvi




  • segmentfault.com/a/1190000007929344



  • Python開發整理髮布,轉載請聯繫作者獲得授權


【點擊成為Java大神】

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python開發 的精彩文章:

談談 Python 的生成器
如何快速成長為優秀程序員?高薪程序員必備工具!

TAG:Python開發 |