Python系列15——正則表達式

目錄

 

一、什麼是正則表達式

二、正則表達式的要素與語法

1、普通字符

2、特殊字符

(1)非打印字符

(3)重複匹配符

3、正則表達式的邏輯與分組

4、正則表達式的函數

(1)findall

(2)split:

(3)replace:

三、常用的正則表達式

1、數字

2、字符

3、特殊需求表達式


​​​​​​​

一、什麼是正則表達式

正則表達式 (Regular Expression) 又稱 RegEx, 是用來匹配字符的一種工具. 在一大串字符中尋找你需要的內容. 它常被用在很多方面, 比如網頁爬蟲, 文稿整理, 數據篩選等等. 最簡單的一個例子, 比如我需要爬取網頁中每一頁的標題. 而網頁中的標題常常是這種形式.

而且每個網頁的標題各不相同, 我就能使用正則表達式, 用一種簡單的匹配方法, 一次性選取出成千上萬網頁的標題信息. 正則表達式絕對不是一天就能學會和記住的, 因爲表達式裏面的內容非常多, 強烈建議, 現在這個階段, 你只需要瞭解正則裏都有些什麼, 不用記住, 等到你真正需要用到它的時候, 再反過頭來, 好好琢磨琢磨, 那個時候纔是你需要訓練自己記住這些表達式的時候.

二、正則表達式的要素與語法

正則表達式是由普通字符(例如字符 a 到 z)以及特殊字符(稱爲"元字符")組成的文字模式。模式描述在搜索文本時要匹配的一個或多個字符串。正則表達式作爲一個模板,將某個字符模式與所搜索的字符串進行匹配。

1、普通字符

普通字符包括沒有顯式指定爲元字符的所有可打印和不可打印字符。這包括所有大寫和小寫字母、所有數字、所有標點符號和一些其他符號。

\d

匹配一個數字

\D

匹配一個非數字

\w

匹配一個字母

\W

匹配一個非字母

[]

可以使用 [] 將可能的字符囊括進來,只能匹配一個字符。

.

匹配除換行符 \n 之外的任何單字符。

\

將下一個字符標記爲或特殊字符、或原義字符、或向後引用、或八進制轉義符。例如, 'n' 匹配字符 'n'。'\n' 匹配換行符。序列 '\\' 匹配 "\",而 '\(' 則匹配 "("。

2、特殊字符

(1)非打印字符

\cx

匹配由x指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須爲 A-Z 或 a-z 之一。否則,將 c 視爲一個原義的 'c' 字符。

\f

匹配一個換頁符。等價於 \x0c 和 \cL。

\n

匹配一個換行符。等價於 \x0a 和 \cJ。

\r

匹配一個回車符。等價於 \x0d 和 \cM。

\s

匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]。注意 Unicode 正則表達式會匹配全角空格符。

\S

匹配任何非空白字符。等價於 [^ \f\n\r\t\v]。

\t

匹配一個製表符。等價於 \x09 和 \cI。

\v

匹配一個垂直製表符。等價於 \x0b 和 \cK。

2)定位符

^

匹配輸入字符串開始的位置。如果設置了 RegExp 對象的 Multiline 屬性,^ 還會與 \n 或 \r 之後的位置匹配。當在一組方括號裏使用 ^ 時,它表示""或"排除"的意思,常常用來剔除某個字符。

$

匹配輸入字符串結尾的位置。如果設置了 RegExp 對象的 Multiline 屬性,$ 還會與 \n 或 \r 之前的位置匹配。

\b

匹配一個單詞邊界。

\B

非單詞邊界匹配。

# \b匹配單詞的邊界
# \b單詞,在單詞前邊不能出現數字、字母、漢字,但是可以出現除此之外的其他符號

>>> print(re.search(r"\brun", "cat is running"))
<re.Match object; span=(7, 10), match='run'>

>>> print(re.search(r"\brun", "cat is !running"))
<re.Match object; span=(8, 11), match='run'>

>>> print(re.search(r"\brun", "cat is *&running"))
<re.Match object; span=(9, 12), match='run'>

>>> print(re.search(r"run\b", "he run!"))
<re.Match object; span=(3, 6), match='run'>

>>> print(re.search(r"run\b", "he run and fail"))
<re.Match object; span=(3, 6), match='run'>
# \B單詞,單詞前邊爲數字或字母
# 單詞\B,單詞後邊爲數字或字母

>>> print(re.search(r"\BMath", "MyMath")) 
<re.Match object; span=(2, 6), match='Math'>

>>> print(re.search(r"\BMath", "1Math")) 
<re.Match object; span=(1, 5), match='Math'>
# ^匹配字符串開頭

>>> print(re.search(r"^welcome", "welcome to beijing"))
<re.Match object; span=(0, 7), match='welcome'>

>>> print(re.search(r"^@", "@胡歌"))
<re.Match object; span=(0, 1), match='@'>
# $匹配字符串的結尾

>>> print(re.search(r"bye$", "趙麗穎,bye"))
<re.Match object; span=(4, 7), match='bye'>


>>> print(re.search(r".beijing", "!beijing"))
<re.Match object; span=(0, 8), match='!beijing'>

 

(3)重複匹配符

*

匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價於{0,}。

+

匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。

?

匹配前面的子表達式零次或一次。例如,"do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 、 "doxy" 中的 "do" 。? 等價於 {0,1}。

{n}

n 是一個非負整數。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。

{n,}

n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價於 'o+'。'o{0,}' 則等價於 'o*'。

{n,m}

m 和 n 均爲非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價於 'o?'。請注意在逗號和兩個數之間不能有空格。

*? 

+?

??

{m,n}?

使得* + ?{m,n}變成非貪婪模式

# +前面表達式重複一次或者多次
# ab+前面表達式變爲ab

>>> print(re.search(r"(ab)+", "ab"))
<re.Match object; span=(0, 2), match='ab'>

>>> print(re.search(r"(ab)+", "beijing and ab"))    
<re.Match object; span=(12, 14), match='ab'>

>>> print(re.search(r"ab+", "beijing")) 
None

>>> print(re.search(r"a-b+", "beijing"))   #表達式爲a-b
None

>>> print(re.search(r"a-b+", "NNNa-bMMM"))
<re.Match object; span=(3, 6), match='a-b'>

 

3、正則表達式的邏輯與分組

|

匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價於{0,}。

(....)

匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。

(?P<name>....)

匹配前面的子表達式零次或一次。例如,"do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 、 "doxy" 中的 "do" 。? 等價於 {0,1}。

# 正則表達式用()來進行分組
# 通過group(i)可以得到不同分組匹配到的字符串

>>> print(re.search(r"(\d+)----(.+)", "123456----北京天安門"))     
<re.Match object; span=(0, 15), match='123456----北京天安門'>

>>> a = re.search(r"(\d+)----(.+)", "123456----北京天安門") 
>>> a.group()   
'123456----北京天安門'

>>> a.group(1) 
'123456'

>>> a.group(2)  
'北京天安門'

 

4、正則表達式的函數

(1)findall

前面我們說的都是隻找到了最開始匹配上的一項而已, 如果需要找到全部的匹配項, 我們可以使用 findall 功能. 然後返回一個列表. 注意下面還有一個新的知識點, | 是 or 的意思, 要不是前者要不是後者.

>>> print(re.findall(r"r[ua]n", "run and ran r2n"))  
['run', 'ran']

>>> print(re.findall(r"(run|ran)", "ruan run runnnran"))      
['run', 'run', 'ran']

(2)split:

再來我們 Python 中有個字符串的分割功能, 比如想獲取一句話中所有的單詞. 比如 "a is b".split(" "), 這樣它就會產生一個列表來保存所有單詞. 但是在正則中, 這種普通的分割也可以做的淋漓精緻.

# split分割函數       
>>> print(re.split(r"[,:\.]","a,b.c:d"))
['a', 'b', 'c', 'd']

(3)replace:

我們還能通過正則表達式匹配上一些形式的字符串然後再替代掉這些字符串. 使用這種匹配 re.sub(), 將會比 python 自帶的 string.replace() 要靈活多變.

# replace替換函數
>>> print(re.sub(r"r[au]nners", "walker", "runners are walking"))     
walker are walking

三、常用的正則表達式

1、數字

  • 數字:^[0-9]*$
  • n位的數字:^\d{n}$
  • 至少n位的數字:^\d{n,}$
  • m-n位的數字:^\d{m,n}$
  • 零和非零開頭的數字:^(0|[1-9][0-9]*)$
  • 非零開頭的最多帶兩位小數的數字:^([1-9][0-9]*)+(\.[0-9]{1,2})?$
  • 帶1-2位小數的正數或負數:^(\-)?\d+(\.\d{1,2})$
  • 正數、負數、和小數:^(\-|\+)?\d+(\.\d+)?$
  • 有兩位小數的正實數:^[0-9]+(\.[0-9]{2})?$
  • 有1~3位小數的正實數:^[0-9]+(\.[0-9]{1,3})?$
  • 非零的正整數:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
  • 非零的負整數:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
  • 非負整數:^\d+$ 或 ^[1-9]\d*|0$
  • 非正整數:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
  • 非負浮點數:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
  • 非正浮點數:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
  • 正浮點數:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
  • 負浮點數:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
  • 浮點數:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

2、字符

  • 漢字:^[\u4e00-\u9fa5]{0,}$
  • 英文和數字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
  • 長度爲3-20的所有字符:^.{3,20}$
  • 由26個英文字母組成的字符串:^[A-Za-z]+$
  • 由26個大寫英文字母組成的字符串:^[A-Z]+$
  • 由26個小寫英文字母組成的字符串:^[a-z]+$
  • 由數字和26個英文字母組成的字符串:^[A-Za-z0-9]+$
  • 由數字、26個英文字母或者下劃線組成的字符串:^\w+$ 或 ^\w{3,20}$
  • 中文、英文、數字包括下劃線:^[\u4E00-\u9FA5A-Za-z0-9_]+$
  • 中文、英文、數字但不包括下劃線等符號:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
  • 可以輸入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
  • 禁止輸入含有~的字符:[^~\x22]+

3​​​​​​​、特殊需求表達式

  • Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
  • 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?
  • InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
  • 手機號碼:^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
  • 電話號碼("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
  • 國內電話號碼(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
  • 電話號碼正則表達式(支持手機號碼,3-4位區號,7-8位直播號碼,1-4位分機號): ((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)
  • 身份證號(15位、18位數字),最後一位是校驗位,可能爲數字或字符X:(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
  • 帳號是否合法(字母開頭,允許5-16字節,允許字母數字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
  • 密碼(以字母開頭,長度在6~18之間,只能包含字母、數字和下劃線):^[a-zA-Z]\w{5,17}$
  • 強密碼(必須包含大小寫字母和數字的組合,不能使用特殊字符,長度在 8-10 之間):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
  • 強密碼(必須包含大小寫字母和數字的組合,可以使用特殊字符,長度在8-10之間):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
  • 日期格式:^\d{4}-\d{1,2}-\d{1,2}
  • 一年的12個月(01~09和1~12):^(0?[1-9]|1[0-2])$
  • 一個月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
  • 錢的輸入格式:
    1. 有四種錢的表示形式我們可以接受:"10000.00" 和 "10,000.00", 和沒有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$
    2. 這表示任意一個不以0開頭的數字,但是,這也意味着一個字符"0"不通過,所以我們採用下面的形式:^(0|[1-9][0-9]*)$
    3. 一個0或者一個不以0開頭的數字.我們還可以允許開頭有一個負號:^(0|-?[1-9][0-9]*)$
    4. 這表示一個0或者一個可能爲負的開頭不爲0的數字.讓用戶以0開頭好了.把負號的也去掉,因爲錢總不能是負的吧。下面我們要加的是說明可能的小數部分:^[0-9]+(.[0-9]+)?$
    5. 必須說明的是,小數點後面至少應該有1位數,所以"10."是不通過的,但是 "10" 和 "10.2" 是通過的:^[0-9]+(.[0-9]{2})?$
    6. 這樣我們規定小數點後面必須有兩位,如果你認爲太苛刻了,可以這樣:^[0-9]+(.[0-9]{1,2})?$
    7. 這樣就允許用戶只寫一位小數.下面我們該考慮數字中的逗號了,我們可以這樣:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
    8. 1到3個數字,後面跟着任意個 逗號+3個數字,逗號成爲可選,而不是必須:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
    9. 備註:這就是最終結果了,別忘了"+"可以用"*"替代如果你覺得空字符串也可以接受的話(奇怪,爲什麼?)最後,別忘了在用函數時去掉去掉那個反斜槓,一般的錯誤都在這裏
  • xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
  • 中文字符的正則表達式:[\u4e00-\u9fa5]
  • 雙字節字符:[^\x00-\xff] (包括漢字在內,可以用來計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1))
  • 空白行的正則表達式:\n\s*\r (可以用來刪除空白行)
  • HTML標記的正則表達式:<(\S*?)[^>]*>.*?|<.*? /> ( 首尾空白字符的正則表達式:^\s*|\s*$或(^\s*)|(\s*$) (可以用來刪除行首行尾的空白字符(包括空格、製表符、換頁符等等),非常有用的表達式)
  • 騰訊QQ號:[1-9][0-9]{4,} (騰訊QQ號從10000開始)
  • 中國郵政編碼:[1-9]\d{5}(?!\d) (中國郵政編碼爲6位數字)
  • IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章