python正則表達式與re模塊-02

  • 2019 年 10 月 7 日
  • 筆記

正則表達式

正則表達式與python的關係

# 正則表達式不是Python獨有的,它是一門獨立的技術,所有的編程語言都可以使用正則  # 但要在python中使用正則表達式,就必須依賴於python內置的re 模塊

驗證手機號是否合法的小案例

while True:      phone_number = input('please input your phone number : ')      if len(phone_number) == 11               and phone_number.isdigit()               and (phone_number.startswith('13')               or phone_number.startswith('14')               or phone_number.startswith('15')               or phone_number.startswith('18')               or phone_number.startswith('19')):          print('是合法的手機號碼')      else:          print('不是合法的手機號碼')
import re  phone_number = input('please input your phone number : ')  if re.match('^(13|14|15|18|19)[0-9]{9}$', phone_number):      print('是合法的手機號碼')  else:      print('不是合法的手機號碼')

從上面兩段代碼中很容易就可以看得出來,使用正則表達式來校驗手機號明顯要比純python 代碼來的精簡得多。

下面就正式介紹一下正則表達式的一些基本知識

正則表達式

正則表達式: # 一種匹配字符串的規則

官方定義: # 正則表達式是對字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個「規則字符串」,這個「規則字符串」用來表達對字符串的一種過濾邏輯。

常見的應用場景: # 爬蟲 , # 數據分析

如果你想系統的學習,可以去了解一下《正則指引》這本書

在開始講正則語法之前,先推薦大家一個驗證正則的網站,可以在線測試你的正則表達式能否滿足你的預期效果:正則表達式在線測試 ,大家可以邊學習邊在該網站上面驗證

你改變正則表達式或者下方的待處理字符串他會自動重新匹配

字符組

# 在同一個位置可能出現的各種字符組成了一個字符組,在正則表達式中用[]表示

常見的字符組(一個字符組中的數據都是 '或' 的關係)

注意: # 字符組可以用 '-' 表示範圍要按照ASCII碼錶的順序書寫,可以 0-9 不可以 9-0,9的ASCII值比0大

字符

常見元字符(推薦按不同顏色來分組記)

注意: # ^ 與 & 會精準限制匹配的內容,兩者中間寫什麼,待匹配的字符串就必須是什麼,多一個少一個都不行 , # 運用 | (「或」)的時候一定要把長的寫在前面,否則匹配到短的就匹配完成了,會有很多被截斷的

分組(): # 當多個正則符號需要重複多次的時候,或者當做一個整體,進行其他操作,那麼可以用分組的形式,分組在正則的語法中就是一個小括號 '(表達式)' ,裏面放表達式即可

轉義字符

觀察上面的元字符可以發現其中有  n t 等代表特殊含義的元字符,如果就是要匹配一個字符串 'n',則會與元字符衝突,故需要在 '' 前面再加上一個 '',來防止轉義,即要表示字符串 'n' 正則中需要寫成 '\n'

量詞

只能跟在元字符/字符組/正則組後面,限制其左邊緊挨着的那個正則表達式(元字符/字符組/正則組),不可兩個量詞連在一起(除了 '?',解除正則的貪婪模式)

*、+、? 推薦如圖所示的畫坐標系的方式記憶

貪婪匹配與非貪婪匹配(惰性匹配)

貪婪匹配: # 在滿足匹配時,匹配儘可能長的字符串

非貪婪匹配: # 在滿足匹配時,匹配儘可能短的字符串

python的匹配模式默認為貪婪匹配,在量詞後面加上 ? 可以將其匹配模式改為非貪婪模式,會匹配盡量少的字符串(僅量詞作用的那個對象會受影響)

貪婪匹配原理個人理解: # 先匹配到目標字符串 '<',然後直接讀取到後面所有的字符串,從倒數第一個字符開始往回找,找到 '>',則將前面的那個位置至這個位置之間的數據返回 ,注意這裡是 .* 任意字符 無限多次!!!

非貪婪原理個人理解: # 先匹配到目標字符串 '<',從該位置開始往後尋找字符 '>',找到則這對數據為一個匹配返回結果 ,注意這裡是 .* 任意字符 無限多次!!!

案例練習

推薦案例 正則表達式練習題 ,可以根據案例鞏固知識

如果你看了本文覺得描述不清,可以參考 re模塊 這篇博客,亦或是下圖的出處的博客  python正則表達式指南 (前者的博客頁面排版看着美觀一些,但大部分數據均來源於後者)

python 中的re模塊

上面只是介紹了正則表達式的一些基礎知識,它是一門獨立的技術,要想在python中使用正則表達式,自然就需要通過學習python內置的re模塊了(也可以通過其他的一些函數方法等方式使用正則)

要使用 re模塊,請不要忘記先導模塊(import re)

本文此部分的參考性可能不高,內容也不是很全面,僅作為個人小結,如果有興趣可以參考 re模塊 裏面有更詳細的講解以及豐富的案例(另:本模塊知識很少用到,所以僅做筆記翻閱)

常見重點函數 findall 找出字符串所有符合內容成一個列表   search 查找匹配結果  match 從開頭開始比對

import re    '''  findall  所有符合正則表達式的所有內容  search  有沒有符合正則表達式的內容  match   是不是正則表達式對應的開頭  '''  # findall 找出字符串中符合正則表達式的所有內容,並且返回一個列表,列表中的元素就是正則表達式匹配到的結果  res = re.findall('[a-z]+', 'nice toZmeet you')  print(res)  # ['nice', 'to', 'meet', 'you']    # search  不會直接返回匹配到的結果,而是給你返回一個對象,這個對象需要調用,通過調用group()方法得到匹配的字符串,如果字符串沒有匹配,則返回None。  # 注意:1.search 只會依據正則查找一次,只要查到了結果,就不會往後查找了  #       2.當查找的結果不存在的情況下,調用group會直接報錯  res = re.search('ou', 'nice toZmeet you')  res2 = res.group()  # 必須調用group 才能看到匹配到的結果  print(res, res2)  # <_sre.SRE_Match object; span=(14, 16), match='ou'> ou  res1 = re.search(r'.', 'nice toZmeet you')  print(res1)  # None  # print(res1.group())  # 直接報錯,if空避免      # match  # 注意:1.match 只會匹配字符串的開頭部分  #       2.當字符串的開頭與正則表達式不符合匹配規則的情況下,返回的也是None,調用 .group 也會報錯  res = re.match('s', 'sda e rf a f')  print(res)  # <_sre.SRE_Match object; span=(0, 1), match='s'>  print(res.group())  # s    '''  正則表達式,返回類型為表達式對象的,如:<_sre.SRE_Match object; span=(6, 7), match='a'>,返回對象時,需要用正則方法取字符串,方法有:      group() # 獲取匹配到的所有結果,不管有沒有分組將匹配到的全部拿出來,有參取匹配到的第幾個如2      groups() # 獲取模型中匹配到的分組結果,只拿出匹配到的字符串中分組部分的結果      groupdict() # 獲取模型中匹配到的分組結果,只拿出匹配到的字符串中分組部分定義了key的組結果  '''

不常用函數 split 切割   sub 替換  compile 將正則編譯成一個對象,可對象. 調用上述方法  finditer 返回一個放返回結果的迭代器

import re    # split 類似於字符串的切割split,返回一個列表(他會把被替換掉的字符變成空格)  res = re.split('[ab]', 'sabcasbdsafafabfas')  print(res)  # ['s', '', 'c', 's', 'ds', 'f', 'f', '', 'f', 's']    # sub 類似於字符串的replace 方法,返回替換完成的字符串,可指定替換次數  # sub('正則表達式', '新的內容', '帶匹配的字符串', [要替換的次數])  #   先按正則表達式查找所有符合該表達式的內容,統一替換成'新的內容',還可以通過n來控制替換的個數  ret = re.sub('d', 'H', 'eva3egon4yuan4', 1)  # 將數字替換成'H',參數1表示只替換1個  print(ret)  # evaHegon4yuan4    # subn() 字符串replace的加強版,返回替換完成的字符串與總共替換的次數(封成了一個元組)  #   返回的是一個元組,元組的第一個元素是替換完成後的結果,第二個元素代表的是替換的個數  ret = re.subn('d', 'H', 'eva3egon4yuan4')  # 將數字替換成'H',返回元組(替換的結果,替換了多少次)  print(ret)  # ('evaHegonHyuanH', 3)      # compile  將正則編譯成一個對象,後期可以直接用它來調用 findall、search 等方法  obj = re.compile('d{3}')  # 將正則表達式編譯成為一個 正則表達式對象,規則要匹配的是3個數字  ret = obj.search('abc123eeee')  # 正則表達式對象調用search,參數為待匹配的字符串  print(ret.group())  # 123      # finditer 返回一個存放匹配結果的迭代器,可以使用前面學習到的 迭代器對象.__next__() 方法調用 ---> 簡寫 next(迭代器對象)  ret = re.finditer('d', 'ds3sy4784a')  print(ret)  # <callable_iterator object at 0x000001AE62617160>  print(next(ret).group())  # 查看第一個結果  # 3  print(next(ret).group())  # 查看第二個結果  # 4  print([i.group() for i in ret])  # 查看剩餘的左右結果  # ['7', '8', '4']

擴展

各方法分組的區別

import re    res = re.search('^[1-9]d{14}(d{2}[0-9x])?$', '110105199812067023')  print(res.group())  # 110105199812067023  print(res.group(1))  # 獲取正則表達式括號闊起來分組的內容  # 023  # print(res.group(2))  # 報錯,取不到     search與match均支持獲取分組內容的操作  跟正則無關是python機制    # 而針對findall它沒有group取值的方法,所以它默認就是分組優先獲取的結果  ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')  print(ret)  # 這是因為findall會優先把匹配結果組裡內容返回,如果想要匹配結果,取消權限即可  # ['oldboy']    ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')  # ?:取消分組優先  print(ret)  # ['www.oldboy.com']
import re    ret = re.search("<(?P<tag_name>w+)>w+</(?P=tag_name)>", "<h1>hello</h1>")  # 還可以在分組中利用?<name>的形式給分組起名字  # 獲取的匹配結果可以直接用group('名字')拿到對應的值  print(ret.group('tag_name'))  # h1  print(ret.group())  # <h1>hello</h1>  """  注意 ?P=tag_name 相當於引用之前正則表達式,並且匹配到的值必須和前面的正則表達式一模一樣  """    # 匹配整數  ret = re.findall(r"d+", "1-2*(60+(-40.35/5)-(-4*3))")  print(ret)  # ['1', '2', '60', '40', '35', '5', '4', '3']    ret = re.findall(r"d+.d*|(d+)", "1-2*(60+(-40.35/5)-(-4*3))")  print(ret)  # ['1', '2', '60', '', '5', '4', '3']  ret.remove("")  print(ret)  # ['1', '2', '60', '5', '4', '3']

爬蟲小案例

'''  本爬蟲案例思路:      分析 https://movie.douban.com/top250?start=%0&filter= 頁面得知,每頁有25條數據      通過分次請求該地址,將返回的HTML代碼通過正則匹配,解析成想要的字符串格式,      分頁分條存入文件中去(用到了 分組 和 取別名 的知識點)  '''  import re  from urllib.request import urlopen      def getPage(url):      response = urlopen(url)      return response.read().decode('utf-8')      def parsePage(s):      com = re.compile(          '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>d+).*?<span class="title">(?P<title>.*?)</span>'          '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)評價</span>', re.S)        ret = com.finditer(s)      for i in ret:          yield {              "id": i.group("id"),              "title": i.group("title"),              "rating_num": i.group("rating_num"),              "comment_num": i.group("comment_num"),          }      def main(num):      url = 'https://movie.douban.com/top250?start=%s&filter=' % num      response_html = getPage(url)      ret = parsePage(response_html)      print(ret)      f = open("move_info7.txt", "a", encoding="utf8")        for obj in ret:          print(obj)          data = str(obj)          f.write(data + "n")      count = 0  for i in range(10):      main(count)      count += 25

數據小樣

上面僅僅只是一個簡單的爬蟲案例,如果你想成為一名爬蟲工程師,那麼你必須的能夠熟練地寫出正則表達式,言下之意就是除了本文的內容,你還需要好好去學學正則表達式的內容