正則表達式

什麼是正則表達式

正則表達式又稱規則表達式 ,許多編程語言都支持利用正則表達式進行字符串操做。Python中的re模塊使 Python 語言擁有所有的正則表達式功能。node

正則表達式是對字符串操做的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個規則字符串,這個規則字符串用來表達對字符串的一種過濾邏輯。正則表達式是一個特殊的字符組合,用來判斷字符串是否與其匹配。python

舉個例子:正則表達式

四條腿活得 —匹配— > 牛編程

以A開頭的四個單詞 —匹配—> 「Andy」編程語言

正則表達式 —匹配— > 字符串函數

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

本文主要介紹Python中re模塊的經常使用 函數。設計

Python原始字符串

正則表達式使用反斜槓字符('\')來表示特殊形式或容許使用特殊字符而不調用其特殊意義。這與Python在字符串文字中的相同目的的使用相同。例如,要匹配文字反斜槓,可能必須將'\\\\'做爲正則表達式字符串,由於正則表達式必須是\\,每一個反斜槓必須在普通的Python字符串文字中表示爲\\調試

解決方案是使用Python的原始字符串符號進行正則表達式模式,在以'r'爲前綴的字符串文字中,反斜槓不以任何特殊的方式處理。因此r'\n'是一個包含「\」「n」的雙字符串,而「\n」是包含換行符的單字符串。code

正則表達式的構成

  1. 普通字符(字符串和數字,例如:abc123)
  2. 元字符(特殊字符,例如:. ^ $ * + ? { } [ ] | ( ) \)

元字符

經常使用元字符表

模式 描述
^ 匹配字符串的開頭。
$ 匹配字符串的結尾。
. 匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則能夠匹配包括換行符的任意字符。
[…] 用來表示一組字符,單獨列出:[amg] 匹配 ‘a’,’m’或’g’。
[^…] 不在[]中的字符:[^abc]匹配除了a,b,c以外的字符。
\w 匹配字母數字及下劃線。
\W 匹配非字母數字及下劃線。
\s 匹配任意空白字符,等價於 [\t\n\r\f]。
\S 匹配任意非空字符。
\d 匹配任意數字,等價於 [0-9]。
\D 匹配任意非數字。
\A 匹配字符串開始。
\Z 匹配字符串結束,若是是存在換行,只匹配到換行前的結束字符串。
\z 匹配字符串結束。
\G 匹配最後匹配完成的位置。
\b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, ‘er\b’ 能夠匹配」never」 中的 ‘er’,但不能匹配 「verb」 中的 ‘er’。
\B 匹配非單詞邊界。’er\B’ 能匹配 「verb」 中的 ‘er’,但不能匹配 「never」 中的 ‘er’。
\n,\t \n: 匹配一個換行符。\t 匹配一個製表符。
* 匹配0個或多個的表達式。
+ 匹配1個或多個的表達式。
? 匹配0個或1個由前面的正則表達式定義的片斷,非貪婪方式。
{n} 精確匹配n個前面表達式。
{n, m} 匹配 n 到 m 次由前面的正則表達式定義的片斷,貪婪方式。
a|b 匹配a或者b。
(…) 匹配括號內的表達式,也表示一個組。

正則表達式修飾符—可選標誌位

正則表達式能夠包含一些可選標誌修飾符來控制匹配的模式。修飾符被指定爲一個可選的標誌。多個標誌能夠經過按位 or(|) 它們來指定。如 re.I | re.M 被設置成 I 和 M 標誌:

修飾符 描述信息
re.A 使\w,\W,\b,\B,\d,\D,\s和\S執行僅與ASCII匹配而不是徹底的Unicode匹配。這隻對Unicode模式有意義,對於字節模式將被忽略。
re.DEBUG 顯示有關編譯表達式的調試信息。
re.I 使匹配對大小寫不敏感。
re.L 作本地化識別(locale-aware)匹配。
re.M 多行匹配,影響 ^ 和 $。
re.S 使 . 匹配包括換行在內的全部字符。
re.X 該標誌經過給予你更靈活的格式以便你將正則表達式寫得更易於理解。

標誌位補充解釋:

  • re.I(re.IGNORECASE)

使匹配對大小寫不敏感;字符類和字符串匹配字母時忽略大小寫。舉個例子,指定這個標識位後,[A-Z]也能夠匹配小寫字母。

  • re.L(re.LOCALE)

影響 「w, 「W, 「b, 和 「B,這取決於當前的本地化設置。

locales 是 C 語言庫中的一項功能,是用來爲須要考慮不一樣語言的編程提供幫助的。舉個例子,若是你正在處理法文文本,你想用 「w+ 來匹配文字,但 「w 只匹配字符類 [A-Za-z];它並不能匹配 「é」 或 「ç」。若是你的系統配置適當且本地化設置爲法語,那麼內部的 C 函數將告訴程序 「é」 也應該被認爲是一個字母。當在編譯正則表達式時使用 LOCALE 標誌會獲得用這些 C 函數來處理 「w 後的編譯對象;這會更慢,但也會象你但願的那樣能夠用 「w+ 來匹配法文文本。

  • re.M(re.MULTILINE)

使用 「^」 只匹配字符串的開始,而 $ 則只匹配字符串的結尾和直接在換行(若是有的話)前的字符串結尾。當指定本標誌後, 「^」 匹配字符串的開始和字符串中每行的開始。一樣的, $ 元字符匹配字符串結尾和字符串中每行的結尾(直接在每一個換行以前)。

  • re.S(re.DOTALL)

使 「.」 特殊字符徹底匹配任何字符,包括換行;沒有這個標誌, 「.」 匹配除了換行外的任何字符。

  • re.X(re.VERBOSE)

該標誌經過給予你更靈活的格式以便你將正則表達式寫得更易於理解。當該標誌被指定時,在 RE 字符串中的空白符被忽略,除非該空白符在字符類中或在反斜槓後面;這可讓你更清晰地組織和縮進re表達式。它也能夠容許你將註釋寫入re表達式,這些註釋會被引擎忽略;註釋用 「#「號 來標識,不過該符號不能在字符串或反斜槓後面。

正則表達式實例:

實例 描述
python 匹配 「python」。
[Pp]ython 匹配 「Python」 或 「python」。
no[bd]e 匹配 「nobe」 或 「node」。
[aeiou] 匹配中括號內的任意一個字母。
[0-9] 匹配任何數字。相似於 [0123456789]。
[a-z] 匹配任何小寫字母。
[A-Z] 匹配任何大寫字母。
[a-zA-Z0-9] 匹配任何字母及數字。
[^aeiou] 除了aeiou字母之外的全部字符。
[^0-9] 匹配除了數字外的字符。

re模塊經常使用方法

re.match

re.match() 嘗試從字符串的起始位置匹配,若是起始位置不能匹配,re.match()就返回None。

語法:

re.match(pattern, string, flags=0)

  • pattern:匹配的正則表達式
  • string:要匹配的字符串
  • flags:標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等。

re.match方法匹配成功後返回一個匹配對象,不然返回None。

import re s = "life is short, you need Python." print(re.match(r'life', s)) # 從開始位置能成功匹配到 print(re.match(r'Life', s, re.I)) # 使用re.I標誌位來指定忽略大小寫 print(re.match(r'life', s).span()) # .span能夠獲取到具體匹配的起始位置 print(re.match(r'Python', s)) # 從開始位置不能成功匹配到 

輸出:

<_sre.SRE_Match object; span=(0, 4), match='life'> <_sre.SRE_Match object; span=(0, 4), match='life'> (0, 4) None 

對於匹配對象能夠使用group(num)和groups()來獲取匹配表達式。

  • group(num=0):匹配的整個表達式的字符串,group() 能夠一次輸入多個組號,在這種狀況下它將返回一個包含那些組所對應值的元組。

  • groups():返回一個包含全部小組字符串的元組,從 1 到 所含的小組號。

import re s = "life is short, you need Python." ret = re.match(r'(.*) is (.*)', s) print("ret.group():", ret.group()) print("ret.group(1, 2):", ret.group(1, 2)) print("ret.group(1):", ret.group(1)) print("ret.group(2):", ret.group(2)) print("ret.groups():", ret.groups()) 

輸出:

ret.group(): life is short, you need Python. ret.group(1, 2): ('life', 'short, you need Python.') ret.group(1): life ret.group(2): short, you need Python. ret.groups(): ('life', 'short, you need Python.') 

分組命名匹配:

(?P<分組的名字>正則規則) 注意:是大寫的P

import re s = "life is short, you need Python." ret = re.match(r'(?P<m1>.*) is (?P<m2>.*)', s) print("ret.group():", ret.group()) print("ret.group('m1'):", ret.group('m1')) # 支持使用組名訪問匹配項 print("ret.group('m2'):", ret.group('m2')) print("ret.group(1, 2):", ret.group(1, 2)) print("ret.group(1):", ret.group(1)) print("ret.group(2):", ret.group(2)) print("ret.groups():", ret.groups()) 

輸出:

ret.group(): life is short, you need Python. ret.group('m1'): life ret.group('m2'): short, you need Python. ret.group(1, 2): ('life', 'short, you need Python.') ret.group(1): life ret.group(2): short, you need Python. ret.groups(): ('life', 'short, you need Python.') 

re.search 掃描整個字符串並返回第一個成功的匹配。

語法:

re.search(pattern, string, flags=0)

  • pattern:匹配的正則表達式。
  • string:要匹配的字符串。
  • flags:標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。

re.search()方法匹配成功後會返回一個匹配的對象,不然返回None。

import re s = "life is short, you need Python." print(re.search(r'life', s)) print(re.search(r'life', s).span()) print(re.search(r'Python', s)) print(re.search(r'Python', s).span()) print(re.search(r'xxx', s)) 

輸出:

<_sre.SRE_Match object; span=(0, 4), match='life'> (0, 4) <_sre.SRE_Match object; span=(24, 30), match='Python'> (24, 30) None 

一樣能夠使用group(num) 或groups() 來獲取匹配表達式。

import re s = "life is short, you need Python." ret = re.search(r'(.*) is (.*)', s) print(ret.group()) print(ret.group(1, 2)) print(ret.group(1)) print(ret.group(2)) print(ret.groups()) 

輸出:

life is short, you need Python. ('life', 'short, you need Python.') life short, you need Python. ('life', 'short, you need Python.') 

re.match和re.search的區別:

re.match只匹配字符串的開始,若是字符串的開始位置不符合正則表達式,則匹配失敗,函數返回None;而re.search匹配整個字符串,直到找到一個匹配,整個字符串都找不到匹配才返回None。

re.split

用匹配到的對象將字符串分割成列表並返回。

語法:

re.split(pattern, string, maxsplit=0, flags=0)

  • pattern:匹配的正則表達式。
  • string:要匹配的字符串。
  • maxsplit:模式匹配後分割的最大次數,默認 0 表示分割全部的匹配。
  • flags:標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。

示例1:

import re s = "Abc123.aBc456.abC789" ret1 = re.split(r'\.', s) # 用.分割字符串s ret2 = re.split(r'\.', s, 1) # 用.分割字符串s,只分割一次 ret3 = re.split(r'[.\d]+', s) # 用.和數字分s print("用.分割字符串s:", ret1) print("用.分割字符串s,只分割一次:", ret2) print("用.和數字分s:", ret3) 

輸出:

用.分割字符串s: ['Abc123', 'aBc456', 'abC789'] 用.分割字符串s,只分割一次: ['Abc123', 'aBc456.abC789'] 用.和數字分s: ['Abc', 'aBc', 'abC', ''] 

注意:

當正則匹配項位於字符串的開頭或結尾時,re.split()獲得列表會有空元素。

re.findall

找到字符串中全部的匹配項,以列表的形式返回。

語法:

re.findall(pattern, string, flags=0)

  • pattern:匹配的正則表達式。
  • string:要匹配的字符串。
  • flags:標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。

示例:

import re s = "Abc123.aBc456.abC789" ret = re.findall(r'\d+', s) # 找到全部的連續數字,並以列表形式返回 print("全部的數字:", ret) 

輸出:

全部的數字: ['123', '456', '789'] 

re.sub

re.sub用來替換字符串中的匹配項。

語法:

re.sub(pattern, repl, string, count=0, flags=0)

  • pattern:匹配的正則表達式。
  • repl:替換的字符串,也可爲一個函數。
  • string:要被查找替換的原始字符串。
  • count:模式匹配後替換的最大次數,默認 0 表示替換全部的匹配。
  • flags:標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。

示例1:

import re s = "life is short, you need Python. # 人生苦短,我用Python。" # 刪除#及後面的內容(把#及後面的字符替換成空字符串) s1 = re.sub(r'#.*$', "", s) print("去掉註釋後:", s1) 

輸出:

去掉註釋後: life is short, you need Python. 

示例2(當repl參數是一個函數時):

import re # 將匹配的數字乘於2 def double(matched): num = int(matched.group("num")) # 注意要轉成int類型 return str(num * 2) # 將乘以2後的結果轉成str類型 s = "1 + 2 = 3" s1 = re.sub(r'(?P<num>\d+)', double, s) # 分組命名匹配 print("re.sub替換後:", s1) 

輸出:

re.sub替換後: 2 + 4 = 6 

re.compile

將正則表達式模式編譯爲正則表達式對象,可用於使用其match()search()方法進行匹配,以下所述。

re_obj = re.compile(pattern)
ret = re_obj.match(string)

等價於:

ret = re.match(pattern, string)

正則表達式練習

練習一

匹配手機號

ret = re.match(r'(1)[3578]\d{9}', s) 

練習二

匹配郵箱

ret = re.match(r'^([a-z.0-9]{1,26})@([a-z.0-9]{1,20})(.[a-z0-9]{1,8})$', s) 

練習三

匹配IP

ret = re.match(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$', s)
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息