Python學習之正則表達式基礎及運用

Python正則表達式

在說Python正則表達式的運用前先講下正則表達式的一些知識,方面大家理解。

正則表達式

正則表達式描述了一種字符串匹配的模式,可以用來檢查一個串是否含有某種子串、將匹配的子串替換或者從某個串中取出符合某個條件的子串等。正則表達式的應用很常見,像手機號、身份證、郵箱的校驗以及應對日常編程開發遇到的文本處理工作。

普通字符、非打印字符和特殊字符:

普通字符:

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

非打印字符:

非打印字符也可以是正則表達式的組成部分。

字符 描述
\cx 匹配由x指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須爲 A-Z 或 a-z 之一。否則,將 c 視爲一個原義的 ‘c’ 字符。記法:control x—>控制某字符
\f 匹配一個換頁符。等價於 \x0c 和 \cL。記法:頁–葉 leaf—>f
\n 匹配一個換行符。等價於 \x0a 和 \cJ。 記法:行—line—>n
\r 匹配一個回車符。等價於 \x0d 和 \cM。 記法:回車—>回去—>return—>r
\s 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]。注意 Unicode 正則表達式會匹配全角空格符。記法:空白—>天是白的—>sky---->s
\S 匹配任何非空白字符。等價於 [^ \f\n\r\t\v]。
\t 匹配一個製表符。等價於 \x09 和 \cI。 記法:表格—>table—>t
\v 匹配一個垂直製表符。等價於 \x0b 和 \cK。記法:垂直—>vertical—>v
特殊字符:

所謂特殊字符,就是一些有特殊含義的字符

許多元字符要求在試圖匹配它們時特別對待。若要匹配這些特殊字符,必須首先使字符"轉義",即,將反斜槓字符\放在它們前面。下表列出了正則表達式中的特殊字符:

特別字符 描述
$ 匹配輸入字符串的結尾位置。如果設置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,請使用 \$
( ) 標記一個子表達式的開始和結束位置。子表達式可以獲取供以後使用。要匹配這些字符,請使用 \(\)
* 匹配前面的子表達式零次或多次。要匹配 * 字符,請使用\*。記法:0*1 =0
+ 匹配前面的子表達式一次或多次。要匹配 + 字符,請使用\+。記法:0+1 = 1
. 匹配除換行符 \n 之外的任何單字符。要匹配 . ,請使用 \.
[ 標記一箇中括號表達式的開始。要匹配 [,請使用 \[
? 匹配前面的子表達式零次或一次或指明一個非貪婪限定符。要匹配 ? 字符,請使用 \?
\ 將下一個字符標記爲或特殊字符、或原義字符、或向後引用、或八進制轉義符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配換行符。序列 ‘\’ 匹配 “”,而 ‘(’ 則匹配 “(”。
^ 匹配輸入字符串的開始位置(除非在方括號表達式中使用),當該符號在方括號表達式中使用時,表示不接受該方括號表達式中的字符集合。要匹配 ^ 字符本身,請使用 \^
{ 標記限定符表達式的開始。要匹配 {,請使用 \{
| 指明兩項之間的一個選擇。要匹配 |,請使用\|

元字符:

限定符

限定符用來指定正則表達式的一個給定組件必須要出現多少次才能滿足匹配。有 ***** 或 +?{n}{n,}{n,m} 共6種。

字符 描述
* 匹配前面的子表達式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。*** 等價於{0,}**。
+ 匹配前面的子表達式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等價於 {1,}
? 匹配前面的子表達式零次或一次。例如,“do(es)?” 可以匹配 “do” 、 “does” 中的 “does” 、 “doxy” 中的 “do” 。? 等價於 {0,1}
{n} n 是一個非負整數(>=0)。匹配前面的表達式確定的 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?’。請注意在逗號和兩個數之間不能有空格。

舉幾個例子:

/[1-9][0-9]*/:匹配大於0的所有數字

/[1-9][0-9]?/:匹配1-99的所有數字,等價於/[1-9][0-9]{0,1}/

`*、+ 限定符都是貪婪的,因爲它們會儘可能多的匹配文字,只有在它們的後面加上一個?就可以實現非貪婪或最小匹配

定位符

即定位正則表達式匹配的位置。定位符與限定符不能一起使用!

字符 描述
^ 匹配輸入字符串開始的位置。
$ 匹配輸入字符串結尾的位置。
\b 匹配一個單詞邊界。正則表達式利用了單詞邊界是單詞和空格之間的位置來進行匹配,例如/\bABC/是在單詞的開始處查找匹配項,/ABC\b/實在單詞結尾處開始查找匹配項,因此\b需要注意匹配位置
\B 匹配非單詞邊界。非單詞邊界,那麼就是單詞的內部(中間部分),例如/\BAbcd/會匹配單詞sdAbcdefg中的Abcd。因此\B不關心匹配位置,只要在單詞內部就行。
其他元字符
字符 描述
[abc] 字符集合,匹配所包含的任意一個字符。並不是匹配abc哦!
[^abc] 匹配未包含的任意一個字符。
[a-z] 匹配指定範圍內的任意字符。(若要匹配連字符-,需要將-放在中括號開頭或結尾,即[-a-z]或[a-z-)
[^a-z] 匹配任何不在指定範圍內的任意字符。
\d 匹配一個數字字符。
\D 匹配一個非數字字符。小技巧,往往變爲大寫的元字符都是對小寫取非
\w 匹配字母、數字、下劃線。等價於'[A-Za-z0-9_]'
\W 匹配非字母、數字、下劃線。等價於'[^A-Za-z0-9_]'
\xn 匹配 n,其中 n 爲十六進制轉義值,即\x43匹配’C’。
\num 匹配 num,其中 num 是一個正整數。例如,’(.)\1’ 匹配兩個連續的相同字符。
(?imx:) 在括號中使用i, m, 或 x 可選標誌
(?-imx: ) 在括號中不使用i, m, 或 x 可選標誌

運算符優先級:

正則表達式從左到右進行計算。

運算符 描述
\ 轉義符
(), (?: ), (?=), [] 圓括號和方括號
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \任何元字符、任何字符 定位點和序列
| 選擇操作符

實例:

^[a-zA-Z0-9_]{1,}$      // 所有包含一個以上的字母、數字或下劃線的字符串 
^[1-9][0-9]{0,}$        // 所有的正整數,等價於 ^[1-9][0-9]*$ 
^\-{0,1}[0-9]{1,}$      // 所有的整數,等價於^\-{0,1}[0-9]+$
^[-]?[0-9]+\.?[0-9]+$   // 所有的浮點數

/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/  //將一個URL解析爲協議、域、端口及相對路徑。
/<\s*(\S+)(\s[^>]*)?>[\s\S]*<\s*\/\1\s*>/    //匹配 HTML 標記。

分組與捕獲

  1. 分組可以分爲兩種形式:捕獲組和非捕獲組
捕獲組:

捕獲組可以從左到右計算其開括號來編號:(a)((b)(c(d)))

那麼(a)在時第一個括號,分爲組1,其次爲((b)(c(d)))、(b)、(c(d))、(d),而組(a)((b)(c(d)))爲組0,組零始終代表整個表達式。

之所以這樣命名捕獲組是因爲在匹配中,保存了與這些組匹配的輸入序列的每個子序列。捕獲的子序列稍後可以通過 Back 引用(反向引用) 在表達式中使用,也可以在匹配操作完成後從匹配器檢索

非捕獲組:

以 (?) 開頭的組是純的非捕獲組,它不捕獲文本 ,也不針對組合計進行計數。

相比較捕獲組,非捕獲組不會將匹配到的內容存放起來,節省了內存。

  • (?:pattern):匹配Pattern字符,不捕獲文本,不將匹配到的字符存儲到內存中,也就是說這是一個非獲取匹配。
industr(?:y|ies)可以匹配industry或industries,等價於industry|industries
  1. (?=pattern):零寬度正先行斷言。僅當子表達式 pattern在此位置的右側匹配時才繼續匹配,即在任何匹配pattern的字符串開始處匹配查找字符串
  2. (?!pattern):零寬度負先行斷言。僅當子表達式pattern不在此位置的右側匹配時才繼續匹配,即在任何不匹配pattern的字符串開始處匹配查找字符串。
  3. (?<=pattern):零寬度正後發斷言。僅當子表達式pattern在此位置的左側匹配時才繼續匹配,與零寬度正先行斷言類似,只是方向相反。
  4. (?<!pattern):零寬度負後發斷言。僅當子表達式pattern不在此位置的左側匹配時才繼續匹配,與零寬度負先行斷言類似,只是方向相反。

因此上述1、3對應,2、4對應。

舉個例子:

(?<!4)56(?=9):匹配後面的文本56前面不能是4,後面必須是9組成。因此,可以匹配如下文本 5569 ,與4569不匹配。

(?<=[^c]a)\d*(?=bd):匹配包含在字符a和b之間的數字,但是這個a之前的字符不能是c;b後面的字符必須是d。

模式修正符

則表達式中常用的模式修正符有i、g、m、s、x、e等。它們之間可以組合搭配使用。

修正符 描述
I 不區分大小寫的匹配,例如/abc/i可以與abc或aBC或ABc等匹配
g 表示全局匹配
M 將字符串視爲多行,不管是那行都能匹配(multiple line)
S 將字符串視爲單行,換行符作爲普通字符(single line)
X 將模式中的空白忽略
A 強制從目標字符串開頭匹配
D 如果使用$限制結尾字符,則不允許結尾有換行,例/abc/D不能與"adshabc\n"匹配
U 只匹配最近的一個字符串,不重複匹配,類似於非貪婪?
e 配合函數preg_replace()使用

Python正則表達式使用

Python的re模塊使 擁有全部的正則表達式功能。

compile 函數根據一個模式字符串和可選的標誌參數生成一個正則表達式對象。該對象擁有一系列方法用於正則表達式匹配和替換。

正則表達式處理函數

  • re.match(pattern, string, flags=0):re.match 嘗試從字符串的起始位置匹配一個模式

    1. pattern:匹配的正則表達式
    2. string:要匹配的字符串
    3. flags:標誌位,用於控制正則表達式的匹配方式,即修飾符

    若匹配成功,則返回一個匹配的對象,否則返回None

    可以使用group(num) 或 groups() 匹配對象函數來獲取匹配表達式。

    方法 描述
    group(num=0) 匹配的整個表達式的字符串,group() 可以一次輸入多個組號,在這種情況下它將返回一個包含那些組所對應值的元組
    groups() 返回一個包含所有小組字符串的元組,從 1 到 所含的小組號。

    看一個實例:

    import re
    str = 'Hey Gril ! I love you so much!'
    match = re.match(r'(.*) love (.*?) .*',str,re.M|re.I)  #()捕獲組
    
    if match:  #如果捕獲到了
       print ("group(0) : ", match.group())  #如前面所講,捕獲組0代表整個表達式,默認值爲0
       print ("group(1) : ", match.group(1)) #打印捕獲組1
       print ("group(2) : ", match.group(2)) #打印捕獲組2
    
    '''
    group(0) :  Hey Gril ! I love you so much!
    group(1) :  Hey Gril ! I
    group(2) :  you
    '''
    
  • re.search(pattern, string, flags=0):re.search 掃描整個字符串返回第一個成功的匹配。

    參數通上re.match()

    同上我們也可以使用group(num) 或 groups() 匹配對象函數來獲取匹配表達式。

    import re
    
    print(re.match('you','I love you'))  #找不到,因爲只能從起始位置可以找
    print(re.search('you','I love you')) #可以找到,因爲時搜索整個字符串
    print(re.search('you','I love you').span())
    
    '''
    None
    <re.Match object; span=(7, 10), match='you'>
    (7, 10)
    '''
    
    import re
    str = 'Hey Gril ! I love you so much!'
    match = re.search(r'(.*) love (.*?) .*',str,re.M|re.I)
    
    if match:  #如果捕獲到了
       print ("group(0) : ", match.group())  #如前面所講,捕獲組0代表整個表達式,默認值爲0
       print ("group(1) : ", match.group(1)) #打印捕獲組1
       print ("group(2) : ", match.group(2)) #打印捕獲組2
       
    ''
    group(0) :  Hey Gril ! I love you so much!
    group(1) :  Hey Gril ! I
    group(2) :  you
    '''
    
  • re.sub(pattern, repl, string, count=0, flags=0):用於替換字符串中的匹配項

    1. pattern:正則表達式中的模式字符串。
    2. repl :替換的字符串,也可以爲一個函數
    3. string:要被查找替換的原始字符串
    4. count:模式匹配後替換的最大次數,默認值爲0,表示替換所有匹配
    5. flags:編譯時用的匹配模式,數字形式

    例子:

    import re
    
    str = "110-119-120 #緊急電話"
    
    num = re.sub(r'#.*$',"",str)
    print(num)
    
    num  = re.sub(r'\D', "",str)
    print(num)
    
    '''
    110-119-120 
    110119120
    '''
    
  • re.compile(pattern[, flags]):compile 函數用於編譯正則表達式,生成一個正則表達式re.RegexObject對象,提供給match() 和 search() 函數使用。

    1. pattern:一個字符串形式的正則表達式
    2. flags:匹配模式
    import re
    pattern = re.compile(r'\d+')
    
    m = pattern.match('one12twothree34four')
    print(m)
    m = pattern.match('one12twothree34four',2,10) 
    print(m)
    m = pattern.match('one12twothree34four',3,10)
    print(m)
    print(m.group(0))
    print(m.start(0))# 獲取分組匹配的子串在整個字符串中的起始位置(子串第一個字符的索引)
    print(m.end(0))# 方法用於獲取分組匹配的子串在整個字符串中的結束位置(子串最後一個字符的索引+1)
    print(m.span(0))# 方法返回 (start(group), end(group))
    
    '''
    None
    None
    <re.Match object; span=(3, 5), match='12'>
    12
    3
    5
    (3, 5)
    '''
    
  • re.findall(string, pos, endpos):從字符串中找到正則表達式所匹配的所有子串,並返回一個列表,如果沒有找到匹配的,則返回空列表。

    1. string:待匹配字符串
    2. pos:可選參數,指定字符串的起始位置,默認爲0
    3. endpos:可選參數,指定字符串的結束位置,默認爲字符串的長度
    import re
    pattern = re.compile(r'[a-z]+')
    
    m1 = pattern.findall('one12twothree34four')
    print(m1)
    m2= pattern.findall('one12twothree34four',4,10)
    print(m2)
    
    '''
    ['one', 'twothree', 'four']
    ['twoth']
    '''
    
  • re.finditer(pattern, string, flags=0):在字符串中找到正則表達式所匹配的所有子串,並把它們作爲一個迭代器返回。是以迭代器返回

    參數同re.match()

    import re
    pattern = re.compile(r'[a-z]+')
    
    m1 = pattern.finditer('one12twothree34four')
    for i in m1:
       print(i.group())
    print('-------------')
    m2= pattern.finditer('one12twothree34four',4,10)
    for i in m2:
       print(i.group())
    '''
    one
    twothree
    four
    -------------
    twoth
    '''
    
  • **re.split(pattern, string[, maxsplit=0, flags=0]):**按照能夠匹配的子串將字符串分割後返回列表

    1. pattern:匹配的正則表達式
    2. string:要匹配的字符串
    3. maxsplit:分隔次數,默認爲0,不限制次數,有就分割
    4. flags:匹配方式
    import re
    print(re.split(r'[0-1]+','one12twothree34four'))
    print(re.split(r'o','one12twothree34four'))
    
    '''
    ['one', '2twothree34four']
    ['', 'ne12tw', 'three34f', 'ur']
    '''
    

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