1. 程式人生 > 程式設計 >Python正則表示式的應用詳解

Python正則表示式的應用詳解

目錄
  • 正則表示式的定義
  • 對正則表示式的支援
    • 示例
      • 例1:驗證輸入的使用者名稱是否有效,使用者名稱由長度為6到20的字母、數字、下劃線組成
      • 例2:從字串中找到與正則表示式匹配的部分
      • 例3:從上獲取新聞的標題和連結
      • 例4:不良內容過濾
      • 例5:用正則表示式拆分字串
  • 總結

    正則表示式的定義

    在編寫處理字串的程時,經常會遇到在一段文字中查詢符合某些規則的字串的需求,正則表示式就是用於描述這些規則的工具,換句話說,我們可以使用正則表示式來定義字串的匹配模式,即如何檢查一個字串是否有跟某種模式匹配的部分或者從一個字串中將與模式匹配的部分提取出來或者替換掉。

    關於正則表示式的相關知識,大家可以閱讀一篇非常有名的博文叫《正則表示式30分鐘入門教程》,讀完這篇文章後你就可以看懂下面的表格,這是我們對正則表示式中的一些基本符號進行的扼要總結。

    QpcRIOwJoy
    符號 解釋 示例 說明
    . 匹配除換行符以外的任意字元 b.t 可以匹配bat / but / b#t / b1t等
    \w 匹配字母/數字/下劃線/漢字 b\wt 可以匹配bat / b1t / b_t等,但不能匹配b#t
    \s 匹配空白字元(包括\r、\n、\t等) love\syou 可以匹配love you
    \d 匹配數字 \d\d 可以匹配01 / 23 / 99等
    \b 匹配單詞的邊界 \bThe\b
    ^ 匹配字串的開始 ^The 可以匹配The開頭的字串
    $ 匹配字串的結束 .exe$ 可以匹配.exe結尾的字串
    \W 匹配非字母/數字/下劃線/漢字 b\Wt 可以匹配b#t / b@t等
    但不能匹配but / b1t / b_t等
    \S 匹配非空白字元 love\Syou 可以匹配love#you等
    但不能匹配love you
    \D 匹配非數字 \d\D 可以匹配9a / 3# / 0F等
    \B 匹配非單詞邊界 \Bio\B
    [] 匹配來自字符集的任意單一字元 [aeiou] 可以匹配任一母音字母字元
    [^] 匹配不在字符集中的任意單一字元 [^aeiou] 可以匹配任一非母音字母字元
    * 匹配0次或多次 \w*
    + 匹配1次或多次 \w+
    ? 匹配0次或1次 \w?
    {N} 匹配N次 \w{3}
    {M,} 匹配至少M次 \w{3,}
    {M,N} 匹配至少M次至多N次 \w{3,6}
    | 分支 foo|bar 可以匹配foo或者bar
    (?#) 註釋
    (exp) 匹配exp並捕獲到自動命名的組中
    (?<name>exp) 匹配exp並捕獲到名為name的組中
    (?:exp) 匹配exp但是不捕獲匹配的文字
    (?=exp) 匹配exp前面的位置 \b\w+(?=ing) 可以匹配I'm dancing中的danc
    (?<=exp) 匹配exp後面的位置 (?<=\bdanc)\w+\b 可以匹配I love dancing and reading中的第一個ing
    (?!exp) 匹配後面不是exp的位置
    (?<!exp) 匹配前面不是exp的位置
    *? 重複任意次,但儘可能少重複 a.*b
    a.*?b
    將正則表示式應用於aabab,前者會匹配整個字串aabab,後者會匹配aab和ab兩個字串
    +? 重複1次或多次,但儘可能少重複
    ?? 重複0次或1次,但儘可能少重複
    {M,N}? 重複M到N次,但儘可能少重複
    {M,}? 重複M次以上,但儘可能少重複

    說明:如果需要匹配的字元是正則表示式中的特殊字元,那麼可以使用\進行轉義處理,例如想匹配小數點可以寫成\.就可以了,因為直接寫.會匹配任意字元;同理,想匹配圓括號必須寫成\(和\),否則圓括號被視為正則表示式中的分組QpcRIOwJoy

    Python對正則表示式的支援

    Python提供了re模組來支援正則表示式相關操作,下面是re模組中的核心函式。

    函式 說明
    compile(pattern,flags=0) 編譯正則表示式返回正則表示式物件
    match(pattern,string,flags=0) 用正則表示式匹配字串 成功返回匹配物件 否則返回None
    search(pattern,flags=0) 搜尋字串中第一次出現正則表示式的模式 成功返回匹配物件 否則返回None
    split(pattern,maxsplit=0,flags=0) 用正則表示式指定的模式分隔符拆分字串 返回列表
    sub(pattern,repl,count=0,flags=0) 用指定的字串替換原字串中與正則表示式匹配的模式 可以用count指定替換的次數
    fullmatch(pattern,flags=0) match函式的完全匹配(從字串開頭到結尾)版本
    findall(pattern,flags=0) 查詢字串所有與正則表示式匹配的模式 返回字串的列表
    finditer(pattern,flags=0) 查詢字串所有與正則表示式匹配的模式 返回一個迭代器
    purge() 清除隱式編譯的正則表示式的快取
    re.I / re.IGNORECASE 忽略大小寫匹配標記
    re.M / re.MULTILINE 多行匹配標記

    說明:上面提到的re模組中的這些函式,實際開發中也可以用正則表示式物件的方法替代對這些函式的使用,如果一個正則表示式需要重複的使用,那麼先通過compile函式編譯正則表示式並創建出正則表示式物件無疑是更為明智的選擇。

    示例

    例1:驗證輸入的使用者名稱是否有效,使用者名稱由長度為6到20的字母、數字、下劃線組成

    方法一:通過compile編譯正則表示式建立Pattern物件,通過給Pattern物件發訊息實現匹配檢查。

    import re
    
    username = input('請輸入使用者名稱:')
    # 通過compile編譯正則表示式建立Pattern物件
    username_pattern = re.compile(r'^\w{6,20}$')
    print(type(username_pattern))
    # 通過給Pattern物件發訊息實現匹配檢查
    matcher = username_pattern.match(uQpcRIOwJoysername)
    print(type(matcher))
    if matcher is None:
        print('無效的使用者名稱')
    else:
        print(matcher.group())
    

    方法二:不建立正則表示式物件,直接呼叫函式進行匹配操作

    username = input('請輸入使用者名稱:')
    matcher = re.fullmatch(r'\w{6,20}',username)
    #^是開始符,$是結束符
    # matcher = re.match(r'^\w{6,20}$',username)
    if matcher is None:
        print('使用者名稱不合法!!!')
    else:
        print(matcher)
        print(matcher.group())
    

    匹配操作可以使用match函式,需要新增開始符號^和結束符號$表示匹配字串的開始與結束;也可以使用fullmatch函式,正則表示式不用寫開始符和結束符。上面在書寫正則表示式時使用了“原始字串”的寫法。

    例2:從字串中找到與正則表示式匹配的部分

    import re
    
    content = """報警電話:110,我們班是Python-2105班,
    我的QQ是9597658,我的手機號是13811223344,謝謝!"""
    
    searcher = re.search(r'1[3-9]\d{9}',content)
    if not searcher:
        print('沒有找到手機號')
    else:
        print(searcher.group())
    

    匹配結果:

    13811223344

    import re
    
    content = """報警電話:110,我們班是Python-2105班,
    我的QQ是9597658,我的手機號是13811223344,謝謝!"""
    
    pattern = re.compile(r'\d+')
    matcher = pattern.search(content)
    while matcher:
        print(matcher.group())
        # 從上一次匹配成功的結束位置開始搜尋
        matcher = pattern.search(content,matcher.end())
    

    匹配結果:

    110
    2105
    9597658
    13811223344

    import re
    
    content = """報警電話:110,我們班是Python-2105班,
    我的QQ是9597658,我的手機號是13811223344,謝謝!"""
    
    pattern = re.compile(r'\d+')
    results = pattern.findall(content)
    # 沒有建立正則表示式物件時,也可以用這種方法
    # results = re.findall(r'\d+',content)
    for result in results:
        print(result)
    

    匹配結果:

    110
    2105
    9597658
    13811223344

    例3:從網頁上獲取新聞的標題和連結

    import re
    
    import requests
    
    resp = requests.get('https://www.sohu.com/')
    # .表示任意字元,+表示匹配一個或任意多個,?表示惰性匹配,儘可能短的匹配
    pattern = re.compile(r'href="http.+?"')
    # 拿到搜狐首頁
    content = resp.text
    matcher = pattern.search(content)
    while matcher:
        print(matcher.group()[6:-1])
        matcher = pattern.search(content,matcher.end())
    
    pattern2 = re.compile(r'title=".+?"')
    title_list = pattern2.findall(content)
    for title in title_list:
        print(title[7:-1])
    

    對於例3,不能使新聞的標題和連結對應起來,如果使用正則表示式捕獲組,可以實現標題和連結的對應。

    import re
    
    import requests
    
    resp = requests.get('https://www.sohu.com/')
    # 匹配整個a標籤,但是隻捕獲()中的內容 ---> 正則表示式的捕獲組
    # .*連在一起就意味著任意數量的不包含換行的字元
    pattern = re.compile(r'<a\s.*?href="(.+?)".*?title="(.+?)".*?>')
    content = resp.text
    results = pattern.findall(content)
    for href,title in results:
        print(title)
        if not href.startswith('https://www.sohu.com'):
            href = 'https://www.sohu.com' + href
        print(href)
    

    例4:不良內容過濾

    import re
    
    content = '你真是一個沙雕煞筆,Fuck you!'
    # pattern = re.compile(r'[傻沙煞][逼筆雕鄙]|馬化騰|fuck|shit',flags=re.IGNORECASE)
    # modified_content = pattern.sub('*',content)
    # print(modified_content)
    # |表示分支
    modified_content = re.sub(r'[傻沙煞][逼筆雕鄙]|fuck|shit','*',content,flags=re.I)
    print(modified_content)
    

    例5:用正則表示式拆分字串

    import re
    
    poem = '床前明月光,疑是地上霜,舉頭望明月,低頭思故鄉。'
    # sentences_list = re.split(r'[,。]',poem)
    # sentences_list = re.split(r',|。',poem)
    pattern = re.compile(r'[,。]')
    sentences_list = pattern.split(poem)
    # sentences_list = [sentence for sentence in sentences_list if sentence]
    # print(sentences_list)
    for sentence in sentences_list:
        print(sentence)
    

    執行結果:

    床前明月光
    疑是地上霜
    舉頭望明月
    低頭思故鄉

    總結

    本篇文章就到這裡了,希望能給你帶來幫助,也希望您能夠多多關注我們的更多內容!