第十六章 Python正則表達式

正則表達式在每種語言中都會有,目的就是匹配符合你預期要求的字符串。html

Python正則表達式主要由re庫提供,擁有了基本全部的表達式。前端

16.1 Python正則表達式python

符號git

描述正則表達式

示例express

. 匹配除換行符(\n)以外的任意單個字符 字符串123\n456,匹配123:1.3
^ 匹配字符串開頭 abc\nxyz,匹配以abc開頭的行:^abc
$ 匹配字符串結尾 abc\nxyz,匹配以xyz結束的行:xyz$
* 匹配多個 hello\nword,匹配以w開頭d結尾的單詞:w*d
+ 匹配1個或多個 abc\nabcc\nadf,匹配abc和abcc:ab+
匹配0個或1個 abc\nac\nadd,匹配abc或ac:a?c
[.] 匹配中括號之中的任意一個字符 abcd\nadd\nbbb,匹配abcd和add:[abc]
[ .-.] 匹配中括號中範圍內的任意一個字符 abcd\nadd\nbbb,匹配abcd和add:[a-c]
[^] 匹配[^字符]以外的任意一個字符 abc\n\abb\nddd,不匹配abc和abb:[^a-c]
{n}或{n,} 匹配花括號前面字符至少n個字符 1\n\12\n123\n1234,匹配123和1234:[0-9]{3}
{n,m} 匹配花括號前面字符至少n個字符,最多m個字符 1\n\12\n123\n1234\n12345,匹配123和1234 :[0-9]{3,4}
| 匹配豎槓兩邊的任意一個 abc\nabd\abe,匹配abc和abd:ab(c|d)
\ 轉義符,將特殊符號轉成原有意義 1.2,匹配1.2:1\.2,不然112也會匹配到


特殊字符緩存

描述運維

示例ide

\A 匹配字符串開始

與^區別是:當使用修飾符re.M匹配多行時,\A將全部字符串做爲一整行處理。函數

abc123\nabc456,匹配abc123:\Aabc,^則都會匹配到

\Z 匹配字符串結束 與\A同理
\b 匹配字符串開始或結束(邊界) abc\nabcd,匹配a開頭而且c結尾字符串:\babc\b
\B 與\b相反
\d 匹配任意十進制數,等效[0-9] 1\n123\nabc,匹配1和123:[0-9],包含單個數字的都會匹配到,若是隻想匹配1:\b[0-9]\b
\D 匹配任意非數字字符,等效[^0-9] 1\n12\nabc,匹配abc:[^0-9]
\s 匹配任意空白字符,等效[\t\n\r\f\v] 1\n a,注意a前面有個空格,匹配a:\s
\S 匹配任意非空白字符,等效[^\t\n\r\f\v] 1\n a\n ,匹配1和a:\S
\w 匹配任意數字和字母,等效[a-zA-Z0-9_] 1\n a\n ,匹配1和a:\w
\W 與\w相反,等效[^a-zA-Z0-9_]
\n 反向引用,n是數字,從1開始編號,表示引用第n個分組匹配的內容 ff,匹配ff:(.)\1,即"ff"


擴展正則表達式

描述

( ) 匹配小括號中正則表達式或字符。用上面\n特殊字符引用。
(?#...) 註釋小括號內的內容
(?:...) 不保存匹配的分組
(?P<name>...) 命名分組,name是標識名稱,默認是數字ID標識分組匹配
(?=...) 匹配後面能匹配表的達式...,稱爲正先行斷言
(?!...) 匹配後面不能匹配的表達式...,稱爲負先行斷言
(?<=...) 匹配前面能匹配的表達式...,稱爲正後發斷言
(?<!...) 匹配前面不能匹配的表達式...,稱爲負後發斷言
(?(id/name)Y/N) 若是分組提供的id或name存在,則使用Y表達式匹配,不然N表達式匹配

斷言:斷言就是一個條件,判斷某個字符串前面或後面是否知足某種規律的字符串,不能引用。

16.2 re庫

re模塊有如下經常使用的方法:

方法

描述

re.compile(pattern, flags=0) 把正則表達式編譯成一個對象
re.findall(pattern, string, flags=0) 以列表形式返回全部匹配的字符串
re.finditer(pattern, string, flags=0) 以迭代器形式返回全部匹配的字符串
re.match(pattern, string, flags=0) 匹配字符串開始,若是不匹配返回None
re.search(pattern, string, flags=0) 掃描字符串尋找匹配,若是符合返回一個匹配對象並終止匹配,不然返回None
re.split(pattern, string, maxsplit=0, flags=0) 以匹配模式做爲分隔符,切分字符串爲列表
re.sub(pattern, repl, string, count=0, flags=0) 字符串替換,repl替換匹配的字符串,repl能夠是一個函數
re.purge() 清除正則表達式緩存

參數說明:

pattern   正則表達式

string    要匹配的字符串

flags     標誌位的修飾符,用於控制表達式匹配模式

標誌位的修飾符,有如下可選項:

修飾符

描述

re.DEBUG 顯示關於編譯正則的debug信息
re.I/re.IGNORECASE 忽略大小寫
re.L/re.LOCALE 本地化匹配,影響\w,\w,\b,\B,\s和\S
re.M/re.MULTILINE 多行匹配,影響^和$
re.S/re.DOTAIL 匹配全部字符,包括換行符\n,若是沒這個標誌將匹配除了換行符
re.U/re.UNICODE 根據unicode字符集解析字符。影響影響\w,\w,\b,\B,\d,\D,\s和\S
re.X/re.VERBOSE 容許編寫更好看、更可讀的正則表達式,也能夠在表達式添加註釋,下面會講到


博客地址:http://lizhenliang.blog.51cto.com

QQ羣:323779636(Shell/Python運維開發羣


16.2.1 re.compile()

把正則表達式編譯成一個對象,方便再次調用:

>>> import re
prog = re.compile(pattern)
result = prog.match(string)
等效於
result = re.match(pattern, string)
例如:檢查字符串是否匹配
>>> def displaymatch(match):
...     if match is None:
...         return None
...     return '<Match: %r, group=%r>' % (match.group(), match.groups())
...
>>> valid = re.compile(r"^[a-c1-3]{3}$")
>>> displaymatch(valid.match("a1b"))   # 可用
"<Match: 'a1b', group=()>"
>>> displaymatch(valid.match("a1b2"))  # 不可用
>>> displaymatch(valid.match("bbb"))   # 可用
"<Match: 'bbb', group=()>"

16.2.1 match()

例如:判斷字符串開頭是否匹配字符
>>> m = re.match(r'hello', 'hello world')           
>>> print m  # 匹配到字符串開頭是hello
<_sre.SRE_Match object at 0x7f56d5634030>
>>> m = re.match(r'world', 'hello world')     
>>> print m  # 沒有匹配到
None

正則對象匹配方法:

1)group([group1, ...])

>>> m = re.match(r'(\w+) (\w+)', 'hello world')    
>>> m.group(0)    # 所有組匹配
'hello world'
>>> m.group(1)    # 第一個括號子組
'hello'
>>> m.group(2)    # 第二個括號子組
'world'
>>> m.group(1, 2) # 多個參數返回一個元組
('hello', 'world')
經過分子重命名的名字來引用分組結果:
>>> m = re.match(r'(?P<first_name>\w+) (?P<last_name>\w+)', 'hello world')    
>>> m.group('first_name')
'hello'
>>> m.group('last_name')
'world'
# 命名組也能夠引用他們的索引
>>> m.group(1)
'hello'
>>> m.group(2)
'world'

若是一組匹配屢次,只有最後一個匹配:

>>> m = re.match(r"(..)+", "a1b2c3")    
>>> m.group(1)
'c3'

2)groups([default])

返回一個元組包含全部子組的匹配。

>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")    
>>> m.groups()
('24', '1632')

3)groupdict([default])

返回子組名字做爲鍵,匹配結果做爲值的字典。

>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "hello world")    
>>> m.groupdict()
{'first_name': 'hello', 'last_name': 'world'}

4)start()和end()

例如:去掉郵件地址的某字符

>>> email = "tony@163_126.com"    
>>> m = re.search(r"_126", email)
>>> email[:m.start()] + email[m.end():]
'tony@163.com'

5)span()

以列表形式返回匹配索引開始和結束值:

>>> email = "tony@163_126.com"    
>>> m = re.search(r"_126", email)
>>> m.span()
(8, 12)

6)pos和endpos

返回字符串開始和結束索引值:

>>> email = "tony@163_126.com"    
>>> m = re.search(r"_126", email)
>>> m.pos
0
>>> m.endpos
16

16.2.3 search()

search()方法也具有match()方法的正則對象匹配方法,區別是search()匹配到第一個後就返回並終止匹配。

例如:匹配第一個結果就返回

>>> m = re.search(r"c", "abcdefc")
>>> m.group()
'c'
>>> m.span()
(2, 3)

16.2.4 split()

例如:以數字做爲分隔符拆分字符串

>>> m = re.split(r"\d+", "a1b2c3")       
>>> m
['a', 'b', 'c', '']
16.2.4 sub()

例如:替換2016

>>> m = re.sub(r"\d+", "2017", "the year 2016")
>>> m
'the year 2017'

例如:repl做爲一個函數

>>> def repl(m):                         
...   return str(int(m.group('v')) * 2)     
...
>>> re.sub(r'(?P<v>\d+)', repl, "123abc")
'246abc'

函數返回必須是一個字符串。

16.2.5 findall()和finditer()

例如:獲得全部匹配的數字

>>> text = "a1b2c3"
>>> re.findall(r'\d+', text)
['1', '2', '3']
>>> for m in re.finditer(r'\d+', text):
...   print m.group()
...
1
2
3

16.2.6 原始字符串符號"r"

上面所看到的(r"\d+")其中的r表明原始字符串,沒有它,每一個反斜槓'\'都必須再加一個反斜槓來轉義它。

例如,下面兩行代碼功能上是相同的:

>>> m = re.match(r"\W(.)\1\W", " ff ")
>>> m.group()
' ff '
>>> m = re.match("\\W(.)\\1\\W", " ff ")
>>> m.group()
' ff '
>>> m = re.match("\W(.)\1\W", " ff ")   
>>> m.group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

\W匹配第一個和最後一個空字符,(.)匹配第一個f,\1引用前面(.)匹配的結果(仍是f),便是r"ff"

16.3 貪婪和非貪婪匹配

貪婪模式:儘量最多匹配

非貪婪模式,儘量最少匹配,通常在量詞(*、+)後面加個問號就是非貪婪模式。

# 貪婪匹配
>>> re.findall(r"<div>.*</div>", "<div>a</div><div>b</div><div>c</div>")
['<div>a</div><div>b</div><div>c</div>']
# 非貪婪匹配
>>> re.findall(r"<div>.*?</div>", "<div>a</div><div>b</div><div>c</div>")
['<div>a</div>', '<div>b</div>', '<div>c</div>']
>>> re.findall(r"a(\d+)", "a123b")     
['123']
>>> re.findall(r"a(\d+?)", "a123b")
['1']
# 若是右邊有限定,非貪婪失效
>>> re.findall(r"a(\d+)b", "a123b")   
['123']
>>> re.findall(r"a(\d+?)b", "a123b")  
['123']

貪婪匹配是儘量的向右匹配,直到字符串結束。

非貪婪匹配是匹配知足後就結束。

16.3 瞭解擴展表達式

以一個字符串來學習斷言的用法:"A regular expression "

1)(?=...)

正先行斷言,匹配後面能匹配的表達式。

有兩個re字符串,只想匹配regular中的:

>>> re.findall(r"..(?=gular)", "A regular expression") 
['re']
# 再向後匹配幾個字符說明匹配的regular中的。下面都會說明下,再也不註釋
>>> re.findall(r"(?=gular).{5}", "A regular expression")
['gular']

2)(?!...)

負先行斷言,匹配後面不能匹配表達式。

只想匹配expression中的re字符串,排除掉regular單詞:

>>> re.findall(r"re(?!g)", "A regular expression") 
['re']
>>> re.findall(r"re(?!g).{5}", "A regular expression")
['ression']

3)(?<=...)

正向後行斷言,匹配前面能匹配表達式。

只想匹配單詞裏的re,排除開頭的re:

>>> re.findall(r"(?<=\w)re", "A regular expression")
['re']
>>> re.findall(r"(?<=\w)re.", "A regular expression")       
['res']

在re前面有一個或多個字符,因此叫後行斷言,正則匹配是從前向後,當遇到斷言時,會再向字符串前端檢測已掃描的字符,相對於掃描方向是向後的。

4)(?<!...)

負向後行斷言,匹配前面不能匹配的表達式。

只想匹配開頭的re:

>>> re.findall(r"(?<!\w)re", "A regular expression") 
['re']
>>> re.findall(r"(?<!\w)re.", "A regular expression")
['reg']

16.4 修飾符

re.VERBOSE上面說明可能你還不太明白,怎麼個更加可讀呢,這就來看看,下面兩個正則編譯等效:

>>> a = re.compile(r"""\d +  # the integral part
...                    \.    # the decimal point
...                    \d *  # some fractional digits""", re.X)
>>> b = re.compile(r"\d+\.\d*")

當你寫的正則很長的時候,能夠添加註釋。


Python正則表達式參考:https://docs.python.org/2/library/re.html

相關文章
相關標籤/搜索