正規表達式在每種語言中都會有,目的就是比對符合你預期要求的字元串。
Python正規表達式主要由re庫提供,擁有了基本所有的表達式。
16.1 Python正規表達式
符号
描述
示例
.
比對除換行符(\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也會比對到
特殊字元
\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()
把正規表達式編譯成一個對象,友善再次調用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<code>>>> </code><code>import</code> <code>re</code>
<code>prog </code><code>=</code> <code>re.</code><code>compile</code><code>(pattern)</code>
<code>result </code><code>=</code> <code>prog.match(string)</code>
<code>等效于</code>
<code>result </code><code>=</code> <code>re.match(pattern, string)</code>
<code>例如:檢查字元串是否比對</code>
<code>>>> </code><code>def</code> <code>displaymatch(match):</code>
<code>... </code><code>if</code> <code>match </code><code>is</code> <code>None</code><code>:</code>
<code>... </code><code>return</code> <code>None</code>
<code>... </code><code>return</code> <code>'<Match: %r, group=%r>'</code> <code>%</code> <code>(match.group(), match.groups())</code>
<code>...</code>
<code>>>> valid </code><code>=</code> <code>re.</code><code>compile</code><code>(r</code><code>"^[a-c1-3]{3}$"</code><code>)</code>
<code>>>> displaymatch(valid.match(</code><code>"a1b"</code><code>)) </code><code># 可用</code>
<code>"<Match: 'a1b', group=()>"</code>
<code>>>> displaymatch(valid.match(</code><code>"a1b2"</code><code>)) </code><code># 不可用</code>
<code>>>> displaymatch(valid.match(</code><code>"bbb"</code><code>)) </code><code># 可用</code>
<code>"<Match: 'bbb', group=()>"</code>
16.2.1 match()
<code>例如:判斷字元串開頭是否比對字元</code>
<code>>>> m </code><code>=</code> <code>re.match(r</code><code>'hello'</code><code>, </code><code>'hello world'</code><code>) </code>
<code>>>> </code><code>print</code> <code>m </code><code># 比對到字元串開頭是hello</code>
<code><_sre.SRE_Match </code><code>object</code> <code>at </code><code>0x7f56d5634030</code><code>></code>
<code>>>> m </code><code>=</code> <code>re.match(r</code><code>'world'</code><code>, </code><code>'hello world'</code><code>) </code>
<code>>>> </code><code>print</code> <code>m </code><code># 沒有比對到</code>
<code>None</code>
正則對象比對方法:
1)group([group1, ...])
18
19
20
<code>>>> m </code><code>=</code> <code>re.match(r</code><code>'(\w+) (\w+)'</code><code>, </code><code>'hello world'</code><code>) </code>
<code>>>> m.group(</code><code>0</code><code>) </code><code># 全部組比對</code>
<code>'hello world'</code>
<code>>>> m.group(</code><code>1</code><code>) </code><code># 第一個括号子組</code>
<code>'hello'</code>
<code>>>> m.group(</code><code>2</code><code>) </code><code># 第二個括号子組</code>
<code>'world'</code>
<code>>>> m.group(</code><code>1</code><code>, </code><code>2</code><code>) </code><code># 多個參數傳回一個元組</code>
<code>(</code><code>'hello'</code><code>, </code><code>'world'</code><code>)</code>
<code>通過分子重命名的名字來引用分組結果:</code>
<code>>>> m </code><code>=</code> <code>re.match(r</code><code>'(?P<first_name>\w+) (?P<last_name>\w+)'</code><code>, </code><code>'hello world'</code><code>) </code>
<code>>>> m.group(</code><code>'first_name'</code><code>)</code>
<code>>>> m.group(</code><code>'last_name'</code><code>)</code>
<code># 命名組也可以引用他們的索引</code>
<code>>>> m.group(</code><code>1</code><code>)</code>
<code>>>> m.group(</code><code>2</code><code>)</code>
如果一組比對多次,隻有最後一個比對:
<code>>>> m </code><code>=</code> <code>re.match(r</code><code>"(..)+"</code><code>, </code><code>"a1b2c3"</code><code>) </code>
<code>'c3'</code>
2)groups([default])
傳回一個元組包含所有子組的比對。
<code>>>> m </code><code>=</code> <code>re.match(r</code><code>"(\d+)\.(\d+)"</code><code>, </code><code>"24.1632"</code><code>) </code>
<code>>>> m.groups()</code>
<code>(</code><code>'24'</code><code>, </code><code>'1632'</code><code>)</code>
3)groupdict([default])
傳回子組名字作為鍵,比對結果作為值的字典。
<code>>>> m </code><code>=</code> <code>re.match(r</code><code>"(?P<first_name>\w+) (?P<last_name>\w+)"</code><code>, </code><code>"hello world"</code><code>) </code>
<code>>>> m.groupdict()</code>
<code>{</code><code>'first_name'</code><code>: </code><code>'hello'</code><code>, </code><code>'last_name'</code><code>: </code><code>'world'</code><code>}</code>
4)start()和end()
例如:去掉郵件位址的某字元
<code>>>> email </code><code>=</code> <code>"tony@163_126.com"</code>
<code>>>> m </code><code>=</code> <code>re.search(r</code><code>"_126"</code><code>, email)</code>
<code>>>> email[:m.start()] </code><code>+</code> <code>email[m.end():]</code>
<code>'[email protected]'</code>
5)span()
以清單形式傳回比對索引開始和結束值:
<code>>>> m.span()</code>
<code>(</code><code>8</code><code>, </code><code>12</code><code>)</code>
6)pos和endpos
傳回字元串開始和結束索引值:
<code>>>> m.pos</code>
<code>0</code>
<code>>>> m.endpos</code>
<code>16</code>
16.2.3 search()
search()方法也具備match()方法的正則對象比對方法,差別是search()比對到第一個後就傳回并終止比對。
例如:比對第一個結果就傳回
<code>>>> m </code><code>=</code> <code>re.search(r</code><code>"c"</code><code>, </code><code>"abcdefc"</code><code>)</code>
<code>>>> m.group()</code>
<code>'c'</code>
<code>(</code><code>2</code><code>, </code><code>3</code><code>)</code>
16.2.4 split()
例如:以數字作為分隔符拆分字元串
<code>>>> m </code><code>=</code> <code>re.split(r</code><code>"\d+"</code><code>, </code><code>"a1b2c3"</code><code>) </code>
<code>>>> m</code>
<code>[</code><code>'a'</code><code>, </code><code>'b'</code><code>, </code><code>'c'</code><code>, '']</code>
<code>16.2</code><code>.</code><code>4</code> <code>sub()</code>
例如:替換2016
<code>>>> m </code><code>=</code> <code>re.sub(r</code><code>"\d+"</code><code>, </code><code>"2017"</code><code>, </code><code>"the year 2016"</code><code>)</code>
<code>'the year 2017'</code>
例如:repl作為一個函數
<code>>>> </code><code>def</code> <code>repl(m): </code>
<code>... </code><code>return</code> <code>str</code><code>(</code><code>int</code><code>(m.group(</code><code>'v'</code><code>)) </code><code>*</code> <code>2</code><code>) </code>
<code>>>> re.sub(r</code><code>'(?P<v>\d+)'</code><code>, repl, </code><code>"123abc"</code><code>)</code>
<code>'246abc'</code>
函數傳回必須是一個字元串。
16.2.5 findall()和finditer()
例如:得到所有比對的數字
<code>>>> text </code><code>=</code> <code>"a1b2c3"</code>
<code>>>> re.findall(r</code><code>'\d+'</code><code>, text)</code>
<code>[</code><code>'1'</code><code>, </code><code>'2'</code><code>, </code><code>'3'</code><code>]</code>
<code>>>> </code><code>for</code> <code>m </code><code>in</code> <code>re.finditer(r</code><code>'\d+'</code><code>, text):</code>
<code>... </code><code>print</code> <code>m.group()</code>
<code>1</code>
<code>2</code>
<code>3</code>
16.2.6 原始字元串符号"r"
上面所看到的(r"\d+")其中的r代表原始字元串,沒有它,每個反斜杠'\'都必須再加一個反斜杠來轉義它。
例如,下面兩行代碼功能上是相同的:
<code>>>> m </code><code>=</code> <code>re.match(r</code><code>"\W(.)\1\W"</code><code>, </code><code>" ff "</code><code>)</code>
<code>' ff '</code>
<code>>>> m </code><code>=</code> <code>re.match(</code><code>"\\W(.)\\1\\W"</code><code>, </code><code>" ff "</code><code>)</code>
<code>>>> m </code><code>=</code> <code>re.match(</code><code>"\W(.)\1\W"</code><code>, </code><code>" ff "</code><code>) </code>
<code>Traceback (most recent call last):</code>
<code> </code><code>File</code> <code>"<stdin>"</code><code>, line </code><code>1</code><code>, </code><code>in</code> <code><module></code>
<code>AttributeError: </code><code>'NoneType'</code> <code>object</code> <code>has no attribute </code><code>'group'</code>
\W比對第一個和最後一個空字元,(.)比對第一個f,\1引用前面(.)比對的結果(還是f),即是r"ff"
16.3 貪婪和非貪婪比對
貪婪模式:盡可能最多比對
非貪婪模式,盡可能最少比對,一般在量詞(*、+)後面加個問号就是非貪婪模式。
<code># 貪婪比對</code>
<code>>>> re.findall(r</code><code>"<div>.*</div>"</code><code>, </code><code>"<div>a</div><div>b</div><div>c</div>"</code><code>)</code>
<code>[</code><code>'<div>a</div><div>b</div><div>c</div>'</code><code>]</code>
<code># 非貪婪比對</code>
<code>>>> re.findall(r</code><code>"<div>.*?</div>"</code><code>, </code><code>"<div>a</div><div>b</div><div>c</div>"</code><code>)</code>
<code>[</code><code>'<div>a</div>'</code><code>, </code><code>'<div>b</div>'</code><code>, </code><code>'<div>c</div>'</code><code>]</code>
<code>>>> re.findall(r</code><code>"a(\d+)"</code><code>, </code><code>"a123b"</code><code>) </code>
<code>[</code><code>'123'</code><code>]</code>
<code>>>> re.findall(r</code><code>"a(\d+?)"</code><code>, </code><code>"a123b"</code><code>)</code>
<code>[</code><code>'1'</code><code>]</code>
<code># 如果右邊有限定,非貪婪失效</code>
<code>>>> re.findall(r</code><code>"a(\d+)b"</code><code>, </code><code>"a123b"</code><code>) </code>
<code>>>> re.findall(r</code><code>"a(\d+?)b"</code><code>, </code><code>"a123b"</code><code>) </code>
貪婪比對是盡可能的向右比對,直到字元串結束。
非貪婪比對是比對滿足後就結束。
16.3 了解擴充表達式
以一個字元串來學習斷言的用法:"A regular expression "
1)(?=...)
正先行斷言,比對後面能比對的表達式。
有兩個re字元串,隻想比對regular中的:
<code>>>> re.findall(r</code><code>"..(?=gular)"</code><code>, </code><code>"A regular expression"</code><code>) </code>
<code>[</code><code>'re'</code><code>]</code>
<code># 再向後比對幾個字元說明比對的regular中的。下面都會說明下,不再注釋</code>
<code>>>> re.findall(r</code><code>"(?=gular).{5}"</code><code>, </code><code>"A regular expression"</code><code>)</code>
<code>[</code><code>'gular'</code><code>]</code>
2)(?!...)
負先行斷言,比對後面不能比對表達式。
隻想比對expression中的re字元串,排除掉regular單詞:
<code>>>> re.findall(r</code><code>"re(?!g)"</code><code>, </code><code>"A regular expression"</code><code>) </code>
<code>>>> re.findall(r</code><code>"re(?!g).{5}"</code><code>, </code><code>"A regular expression"</code><code>)</code>
<code>[</code><code>'ression'</code><code>]</code>
3)(?<=...)
正向後行斷言,比對前面能比對表達式。
隻想比對單詞裡的re,排除開頭的re:
<code>>>> re.findall(r</code><code>"(?<=\w)re"</code><code>, </code><code>"A regular expression"</code><code>)</code>
<code>>>> re.findall(r</code><code>"(?<=\w)re."</code><code>, </code><code>"A regular expression"</code><code>) </code>
<code>[</code><code>'res'</code><code>]</code>
在re前面有一個或多個字元,是以叫後行斷言,正則比對是從前向後,當遇到斷言時,會再向字元串前端檢測已掃描的字元,相對于掃描方向是向後的。
4)(?<!...)
負向後行斷言,比對前面不能比對的表達式。
隻想比對開頭的re:
<code>>>> re.findall(r</code><code>"(?<!\w)re"</code><code>, </code><code>"A regular expression"</code><code>) </code>
<code>>>> re.findall(r</code><code>"(?<!\w)re."</code><code>, </code><code>"A regular expression"</code><code>)</code>
<code>[</code><code>'reg'</code><code>]</code>
16.4 修飾符
re.VERBOSE上面說明可能你還不太明白,怎麼個更加可讀呢,這就來看看,下面兩個正則編譯等效:
<code>>>> a </code><code>=</code> <code>re.</code><code>compile</code><code>(r</code><code>"""\d + # the integral part</code>
<code>... \. # the decimal point</code>
<code>... \d * # some fractional digits"""</code><code>, re.X)</code>
<code>>>> b </code><code>=</code> <code>re.</code><code>compile</code><code>(r</code><code>"\d+\.\d*"</code><code>)</code>
當你寫的正則很長的時候,可以添加注釋。
本文轉自 李振良OK 51CTO部落格,原文連結:http://blog.51cto.com/lizhenliang/1877675,如需轉載請自行聯系原作者