Python學習之正則

Python學習目錄python

  1. 在Mac下使用Python3
  2. Python學習之數據類型
  3. Python學習之函數
  4. Python學習之高級特性
  5. Python學習之函數式編程
  6. Python學習之模塊
  7. Python學習之面向對象編程
  8. Python學習之面向對象高級編程
  9. Python學習之錯誤調試和測試
  10. Python學習之IO編程
  11. Python學習之進程和線程
  12. Python學習之正則
  13. Python學習之經常使用模塊
  14. Python學習之網絡編程

正則表達式是一種用來匹配字符串的強有力的武器。它的設計思想是用一種描述性的語言來給字符串定義一個規則,凡是符合規則的字符串,咱們就認爲它「匹配」了,不然,該字符串就是不合法的。正則表達式

正則

基本

在正則表達式中,若是直接給出字符,就是精確匹配。用\d能夠匹配一個數字,\w能夠匹配一個字母或數字,因此:編程

  • '00\d'能夠匹配'007',但沒法匹配'00A'
  • '\d\d\d'能夠匹配'010'
  • '\w\w\d'能夠匹配'py3'

.能夠匹配任意字符,因此:bash

  • 'py.'能夠匹配'pyc''pyo''py!'等等。

要匹配變長的字符,在正則表達式中,用*表示任意個字符(包括0個),用+表示至少一個字符,用?表示0個或1個字符,用{n}表示n個字符,用{n,m}表示n-m個字符:網絡

來看一個複雜的例子:\d{3}\s+\d{3,8}函數式編程

咱們來從左到右解讀一下:函數

  1. \d{3}表示匹配3個數字,例如'010'
  2. \s能夠匹配一個空格(也包括Tab等空白符),因此\s+表示至少有一個空格,例如匹配' '' '等;
  3. \d{3,8}表示3-8個數字,例如'1234567'

綜合起來,上面的正則表達式能夠匹配以任意個空格隔開的帶區號的電話號碼。post

若是要匹配'010-12345'這樣的號碼呢?因爲'-'是特殊字符,在正則表達式中,要用'\'轉義,因此,上面的正則是\d{3}\-\d{3,8}學習

可是,仍然沒法匹配'010 - 12345',由於帶有空格。因此咱們須要更復雜的匹配方式。測試

進階

要作更精確地匹配,能夠用[]表示範圍,好比:

  • [0-9a-zA-Z\_]能夠匹配一個數字、字母或者下劃線;
  • [0-9a-zA-Z\_]+能夠匹配至少由一個數字、字母或者下劃線組成的字符串,好比'a100''0_Z''Py3000'等等;
  • [a-zA-Z\_][0-9a-zA-Z\_]*能夠匹配由字母或下劃線開頭,後接任意個由一個數字、字母或者下劃線組成的字符串,也就是Python合法的變量;
  • [a-zA-Z\_][0-9a-zA-Z\_]{0, 19}更精確地限制了變量的長度是1-20個字符(前面1個字符+後面最多19個字符)。

A|B能夠匹配A或B,因此(P|p)ython能夠匹配'Python'或者'python'

^表示行的開頭,^\d表示必須以數字開頭。

$表示行的結束,\d$表示必須以數字結束。

你可能注意到了,py也能夠匹配'python',可是加上^py$就變成了整行匹配,就只能匹配'py'了。

re模塊

有了準備知識,咱們就能夠在Python中使用正則表達式了。Python提供re模塊,包含全部正則表達式的功能。因爲Python的字符串自己也用\轉義,因此要特別注意:

s = 'ABC\\-001' # Python的字符串
# 對應的正則表達式字符串變成:
# 'ABC\-001'
複製代碼

所以咱們強烈建議使用Python的r前綴,就不用考慮轉義的問題了:

s = r'ABC\-001' # Python的字符串
# 對應的正則表達式字符串不變:
# 'ABC\-001'
複製代碼

先看看如何判斷正則表達式是否匹配:

>>> import re
>>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>
>>> re.match(r'^\d{3}\-\d{3,8}$', '010 12345')
>>>
複製代碼

match()方法判斷是否匹配,若是匹配成功,返回一個Match對象,不然返回None。常見的判斷方法就是:

test = '用戶輸入的字符串'
if re.match(r'正則表達式', test):
    print('ok')
else:
    print('failed')
複製代碼

分組

除了簡單地判斷是否匹配以外,正則表達式還有提取子串的強大功能。用()表示的就是要提取的分組(Group)。好比:

^(\d{3})-(\d{3,8})$分別定義了兩個組,能夠直接從匹配的字符串中提取出區號和本地號碼:

>>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
>>> m
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>
>>> m.group(0)
'010-12345'
>>> m.group(1)
'010'
>>> m.group(2)
'12345'
複製代碼

若是正則表達式中定義了組,就能夠在Match對象上用group()方法提取出子串來。

注意到group(0)永遠是原始字符串,group(1)group(2)……表示第一、二、……個子串。

提取子串很是有用。來看一個更兇殘的例子:

>>> t = '19:05:30'
>>> m = re.match(r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$', t)
>>> m.groups()
('19', '05', '30')
複製代碼

這個正則表達式能夠直接識別合法的時間。可是有些時候,用正則表達式也沒法作到徹底驗證,好比識別日期:

'^(0[1-9]|1[0-2]|[0-9])-(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$'
複製代碼

對於'2-30''4-31'這樣的非法日期,用正則仍是識別不了,或者說寫出來很是困難,這時就須要程序配合識別了。

貪婪匹配

最後須要特別指出的是,正則匹配默認是貪婪匹配,也就是匹配儘量多的字符。舉例以下,匹配出數字後面的0

>>> re.match(r'^(\d+)(0*)$', '102300').groups()
('102300', '')
複製代碼

因爲\d+採用貪婪匹配,直接把後面的0所有匹配了,結果0*只能匹配空字符串了。

必須讓\d+採用非貪婪匹配(也就是儘量少匹配),才能把後面的0匹配出來,加個?就可讓\d+採用非貪婪匹配:

>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
('1023', '00')
複製代碼

編譯

當咱們在Python中使用正則表達式時,re模塊內部會幹兩件事情:

  1. 編譯正則表達式,若是正則表達式的字符串自己不合法,會報錯;
  2. 用編譯後的正則表達式去匹配字符串。

若是一個正則表達式要重複使用幾千次,出於效率的考慮,咱們能夠預編譯該正則表達式,接下來重複使用時就不須要編譯這個步驟了,直接匹配:

>>> import re
# 編譯:
>>> re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
# 使用:
>>> re_telephone.match('010-12345').groups()
('010', '12345')
>>> re_telephone.match('010-8086').groups()
('010', '8086')
複製代碼

編譯後生成Regular Expression對象,因爲該對象本身包含了正則表達式,因此調用對應的方法時不用給出正則字符串。

下一篇:Python學習之經常使用模塊

相關文章
相關標籤/搜索