Pyhton_語法綜述_re模塊和正則表達式_常用詳解(15)

建議第一節閱讀,到第二節可以對照第一節查看使用

一、re模塊

(一)關於正則表達式介紹

  • 1.數據抓取,數據提取,如:抓取網站中的圖片地址
  • 2.數據清洗:把不雅的評論清洗掉
  • 3.數據驗證:驗證手機號的合法性

正則表達式:是一種字符串的查詢和匹配規則,按照提供的規則完成目標字符串中的數據的查詢和檢索。
50年代,神經學、精神學兩位科學家嘗試將大腦中認知事物的方式描述出來,最終沒 有成功。70 年代數學家看到了兩位科學家筆記/筆錄,聯合另外一位生物學家一起將人類大腦認知事物的方式,使用數學表達式第一次簡單的描述了出來,並沒有出現實際的應用價值。肯·湯普森(Unix 之父):學校實驗室打工,自己想玩遊戲,搭建遊戲平臺→ 研發第一代的Unix 操作系統,在操作系統中爲了能快速的檢索字符串信息,研究各種文獻發現了數學家發表的論文,將正確規則描述事物的方式-正則表達式-在 Unix操作系統中第一次實現了出來並且取得了非常好的效果。
正則表達式在發展過程中,晨露崢嶸,被很多編程語言所接納,各種編程語言在構建語法規則的過程中,紛紛表示支持正則表達式的操作語法。python:支持正則表達式語法操作的模塊:re

	項目需求:錄入資料--手機號碼
	    要求:長度11位、都是數字、156|188開頭

比較傳統解決思路,和使用正則表達的思路,發現,正則表達代碼優化更好!
① 傳統代碼的驗證方式

phone = input("請輸入您的手機號碼:")

def common_verify(phone):
    # 判斷長度
    if len(phone) == 11:
        # 判斷開頭
        if phone.startswith("156") or phone.startswith("188"):
            # 判斷數字
            for x in phone:
                if not x.isdigit(): # 是數字
                    break
            else:
                # 合法手機號碼
                input("這是一個合法的手機號碼")
                return True
    # 非法手機號碼
    input("這是一個非法的手機號碼")
    return False

print(common_verify(phone))

輸入正確的結果圖:
在這裏插入圖片描述
錯誤的結果:
在這裏插入圖片描述
② 正則表達式的驗證方式

import re

phone = input("請輸入您的手機號碼:")

def re_verify(phone):
    """驗證手機號碼是否合法的函數"""
    # 定義一個正則表達式
    vp = r"(156|188)\d{8}"
    return True if len(re.findall(vp, phone)) > 0 else False

re_verify(phone)

(二)Python中操作正則表達式

Python 提供的正則表達式處理模塊 re,提供了各種正則表達式的處理函數

● 使用過程 【不一定是這種結構,以最簡單說明】:

	1.導入模塊 import re
	2.匹配,ret = re.match("正則 表達式公式", "要匹配的字符串")
	3.判斷是否成功
				ret: 不爲空,表示匹配成功,返回match對象
						爲空,匹配失敗
	4.取匹配結果   ret。group()
	注意:re.match():匹配xxx開頭的字符串

● 對應代碼說明:

# 匹配 "csdn"

import re
ret = re.match("csdn","csdn.com")  # 從頭開始匹配

if ret:
    print(ret.group())
    print(ret)
else:
    print("匹配成功")

在結果此處,可以看到有一個"CSDN",這是ret.group()直接查看結果的,而剩下哪行則是對象
在這裏插入圖片描述

(三)字符查詢匹配函數

官方 re.py 可以查看註釋,本篇文章主要講解常用的,並且本文基本基於match函數講解
在這裏插入圖片描述
在這裏插入圖片描述
對於函數簡單的做一個說明

函數 說明
re.match(reg,info) 用於在 開始位置[從左往右] 匹配目標字符串info,符合正則表達式reg,會返回一個match對象,匹配不成功返回None
re.search(reg,info) ) 掃描整個字符串info,符合正則表達式reg,返回一個match對象,否則None
re.findall(reg,info) 掃描整個字符串info,符合正則表達式reg字符串, 提取出來,存放到列表中
re.fullmatch(reg,info) 掃描整個字符串,字符串在正則表達式reg限定範圍,返回整個字符串,否則None
re.finditer(reg,info) 掃描整個字符串,將匹配到的字符保存在一個可以遍歷的列表中

(四)字符串拆分替換函數

函數 說明
re.split(reg,string) 正則表達式reg,將字符串string 才分成一個字符串列表,如:re.split(r"\s+",string),表示使用一個或者多個空白字符對字符串info進行拆分,並返回一個拆分後的字符串列表
re.sub(reg,repl,string) 使用指定的字符串repl來替換字符串string中匹配的正則表達式reg的字符

(五)正則表達式元字符

使用正則表達式時,用到了一些包含特殊含義的字符,用於表示字符串中一些特殊的位置, 非常重要,我們先簡單瞭解一下一些常用的元字符

元字符 描述
^ 表示匹配字符串的開頭位置 在 [ ] 中使用代表取反
$ 表示匹配字符串的結束位置的字符
. 表示匹配任意一個字符
\d 匹配一個數字字符
\D 匹配一個非數字字符
\s 匹配一個空白字符
\S 匹配一個非空白字符
\w 匹配一個數字/字母/下劃線中任意一個字符
\W 匹配一個非數字字母下劃線的任意一個字符 Python3 中文也算
\b 匹配一個單詞的邊界
\B 匹配不是單詞的開頭或者結束位置

(六)正則表達式中的量詞

量詞,用於限定字符出現數量的關鍵字

量詞 描述
x* 用於匹配符號*前面的字符出現0次或者多次
x+ 用於匹配符號+前面的字符出現1次或者多次
x? 用於匹配符號?前面的字符出現0次或者1次
x{n} 用於匹配符號{n}前面的字符出現n次
x{m,n} 用於匹配符號{m,n} 前面的字符出現至少m次,最多n次
x{n,} 用於匹配符號{n,}前面的字符出現至少n次

(七)正則表達式範圍匹配

在正則表達式中,針對字符的匹配,除了快捷的元字符的匹配,還有另一種使用方括號進行 的範圍匹配方式,具體如下:

範圍 說明
[0-9] 用於匹配一個0~9之間的數字,等價於\d
[^0-9] 用於匹配一個非數字字符,等價於\D
[3-6] 用於匹配一個3~6之間的數字
[a-z] 用於匹配一個a~z之間的字母
[A-Z] 用於匹配一個A~Z之間的字母
[a-f] 用於匹配一個a~f之間的字母
[a-zA-Z] 用於匹配一個a-z或者A-Z之間的字母,匹配任意一個字母
[a-zA-Z0-9] 用於匹配一個字母或者數字
[a-zA-Z0-9] 用於匹配一個字母或者數字或者下劃線,等價於\w
[^a-zA-Z0-9] 用於匹配一個非字母或者數字或者喜愛劃線,等價於\w

(八)正則表達式分組

正則表達式主要是用於進行字符串檢索匹配操作的利器,在一次完整的匹配過程中,可以將 匹配到的結果進行分組,這樣就更加的細化了我們對匹配結果的操作,正則表達式通過圓括 號()進行分組,以提取匹配結果的部分結果。常用的兩種分組:

分組 描述
(expression) 使用圓括號直接分組;正則表達式本身匹配的結果就是一個組,可以通過group()或者group(0)獲取;然後正則表達式中包含的圓括號就是按照順序從1開始編號的小組
(?Pexpression) 使用圓括號分組,然後給當前的圓括號表示的小組命名爲name,可以通過group(name)進行數據的獲取

(九)貪婪模式和懶惰模式

貪婪模式:從目標字符串的兩頭開始搜索,一次儘可能多的匹配符合條件的字符串,但是有 可能會匹配到不需要的內容,正則表達式中的元字符、量詞、範圍等都模式是貪婪匹配模式, 使用的時候一定要注意分析結果:

`<div>.*</div>就是一個貪婪模式,用於匹配<div></div>之間所有的字符

懶惰模式: 從目標字符串按照順序從頭到位進行檢索匹配,儘可能的檢索到最小範圍的匹配 結果,語法結構是在貪婪模式的表達式後面加上一個符號?即可,

<div>.*?</div>就是一個 懶惰模式的正則,用於僅僅匹配最小範圍的<div></div>之間的內容

二、正則表達常用案例

1、正則表達基本使用

# 匹配 "csdn"

import re

ret = re.match("csdn","csdn.com")  # 從頭開始匹配

if ret:
    print(ret.group())
    print(ret)
else:
    print("匹配成功")

2、匹配單個字符

"""
    常用的
"""

import re


# 1. “.”  : 表示匹配任意一個字符,除了\n(換行符)以外
# 案例:看電影,輸入電影名稱:“速度與激情”時,“激”字符可以任意輸入,都算成功
# ret = re.match("速度與.情","速度與激情123123")
# print(ret)


# 2. [] : 匹配 “ []”列舉的字符
# 案例:看電影,輸入電影名稱:“速度與激情”時,“速度與激情1”時 和 “速度與激情2”都正確

# ret = re.match("速度與激情[1245678]","速度與激情1") # 成功
# ret = re.match("速度與激情[1245678]","速度與激情a") # None
# ret = re.match("速度與激情[1245678]","速度與激情10") # 需要完善
# ret = re.match("速度與激情[1-8]","速度與激情8") # 另外個寫法,成功 簡化


# “速度與激情6”不匹配
# ret = re.match("速度與激情[1-57-8]","速度與激情6") #None
# ret = re.match("速度與激情[a-z]","速度與激情a") #成功,如果是註冊也可以
# print(ret)


# 3. \d :匹配數字,0-9
# ret = re.match("速度與激情\d","速度與激情6") #成功

# 4. \D :匹配非數字
# ret = re.match("速度與激情\D","速度與激情6") #None
# ret = re.match("速度與激情\D","速度與激情a") #成功
# print(ret)


# 5. \s 匹配空格,包含空格和tab
# ret = re.match("速度與激情\s","速度與激情  ") #成功
# ret = re.match("速度與激情\s","速度與激情a") #None
# ret = re.match("速度與激情\s","速度與激情 a") #成功
# print(ret)

# 6. \S 匹配空格,只要不是空格都匹配
# ret = re.match("速度與激情\S","速度與激情a")#成功
# ret = re.match("速度與激情\S","速度與激情")#None
# print(ret)

# 7. \w 匹配單詞字符:包含(a-z,A-Z,0-9,_下劃線)
#       在python3 中,中文字符包含在單詞字符中
# ret = re.match("\w","1")#成功
# ret = re.match("\w","a")#成功
# ret = re.match("\w","_")#成功
# ret = re.match("\w","@")#None
# ret = re.match("\w","穩")#成功 !!
# print(ret)

# 8. \W 匹配非單詞字符
# ret = re.match("\W","@")#成功
# ret = re.match("\W","=")#成功
# ret = re.match("\W","張")#None
ret = re.match("\W","a")#None
print(ret)

3、匹配多個字符

import re



# 1.{m} : 匹配前一個字符出現m次
# 匹配合法手機號
# 規則 要求滿足11位,並且第一位是 1

# ret = re.match("\d{11}","12345687901")# 成功 判斷規則:數字+11位
# ret = re.match("1\d{10}","12345687901")# 成功 除了第一位,往後10位匹配
# ret = re.match("1\d{10}","42345687901")# None 開頭不爲1
# ret = re.match("1\d{10}","1234fg68791")# None 包含了字母
# ret = re.match("1\d{10}","12345687901asd")# 成功,10後 沒有參與匹配
# print(ret)


# 2.{m,n} : 匹配前一個字符出現m到n次
# 驗證電話號碼的合法性 如:010-1234567,0558-8080255
# 規則:區號3-4位數字,電話號是7-8位,中間用“ - ” 連接
# ret = re.match("\d{3,4}-\d{7,8}","010-12345678")#成功
# ret = re.match("\d{3,4}-\d{7,8}","0558-8080255")#成功
# ret = re.match("\d{3,4}-\d{7,8}","0558-8080255a")#成功
# print(ret)

# 3.?: 前一個字符出現0次或者1次,要麼出現1次,要麼出現0次
# 驗證電話號碼的合法性 如:010-1234567,0558-8080255
# 規則:區號3-4位數字,電話號是7-8位,中間用“ - ” ,“-”可有可無
# ret = re.match("\d{3,4}-\d{7,8}","0101234567")#None
# # ret = re.match("\d{3,4}-?\d{7,8}","0101234567")#成功
# ret = re.match("\d{3,4}-?\d{7,8}","010@1234567")#None
# print(ret)

# 4. * : 匹配前一個字符出現0次或多次
# 要求:把一個文本內容全部提取出來

# content = "life is short, I use Python !"
# ret = re.match(".",content) # 匹配的第一個
# ret = re.match(".*",content) # 匹配所有,只能匹配一行

# content = "life is short, I use \n Python !"
# ret = re.match(".*",content,re.S) # re.S 可以匹配多行

# ret  = re.match(".*","") # 成功
# print(ret)

# 5. + :匹配前一個字符,出現1次或者多次,即至少出現1次
# ret  = re.match("a+","aaaa")# 成功
ret  = re.match("a+","")# None
print(ret)


4、匹配開頭和結尾

import re
# 1. ^ :匹配開頭的字符串

# ret = re.match("csdn","csdn.com") # 成功
# ret = re.match("csdn","www.csdn.com") # None
# ret = re.search("csdn","www.csdn.com") # 成功
# ret = re.search("^csdn","www.csdn.com") # None
# print(ret)

# 注意用在[]表示取反
# ret = re.match("速度與激情[^6]","速度與激情9") # 成功
# ret = re.match("速度與激情[1-57-9]","速度與激情9") # 成功
# print(ret)

# 2. $ :匹配以XXX結尾的字符串
# 匹配出合法的手機號
# 規則:11位數字 且第一位是1

# ret = re.match("1\d{10}","12345678901") # 成功
# ret = re.match("1\d{10}","12345678901abc") # 成功 後面字母沒有匹配,不符合
ret = re.match("1\d{10}$","12345678901abc") # None
print(ret)

5、案例操作[ 匹配爬取郵箱,合法名判斷]

import re



# 1、匹配出合法的變量名
# 匹配規則:字符由數字,字母,下劃線組成,首字符不能是數字
names = ["age1","1age","AGO_","_9age","age_","a9#_2","a#ge"]

for i in names:

    ret = re.match("[a-zA-Z_]\w*",i) #
    if ret :
        print(f"{i}是合法的")
    else:
        print(f"{i}不合法")

# 2、匹配合法的163郵箱
# 匹配規則:每個郵箱以“@163.com”結尾,@之前4-20單詞字符
# email_list = ["[email protected]","[email protected]","[email protected]","[email protected]","liang@163ccom"]
# for a in email_list:
#     ret = re.match("\w{4,20}@163\.com$",a)
#     if ret:
#      print(f"{a}是合法的")
#     else:
#         print(f"{a}不合法")


6、匹配分組

import re

# 1. | : 匹配左右任意一個表達式 管道符

# email_list = ["[email protected]","[email protected]","[email protected]","[email protected]","liang@163ccom"]
# for a in email_list:
#     ret = re.match("\w{4,20}@163\.com$|\w{4,20}@126\.com|\w{4,20}@qq\.com",a)
#     if ret:
#      print(f"{a}是合法的")
#     else:
#         print(f"{a}不合法")

# 2、 (ab):分組

# A、引入
email = "[email protected]"
ret = re.match("(\w{4,20})@qq\.com",email)
print(ret.group())
print(ret.group(1))

# email_list = ["[email protected]","[email protected]","[email protected]","[email protected]","liang@163ccom"]
# for a in email_list:
#     ret = re.match("\w{4,20}@(163|qq|126)\.com$",a)
#     if ret:
#      print(f"{a}是合法的")
#     else:
#         print(f"{a}不合法")

# 3、引用分組 \num:  引用分組匹配到的字符串
# 檢查html網頁的合法性
# 語法規則:標籤必須配對
# content = "<h1>hello world</h1>" # 前後配對 合法
# content = "<h1>hello world</h1>" # 前後不配對也合法
# ret = re.match("<\w+>.*</\w+>",content) # 不嚴謹的寫法
# ret = re.match("<(\w+)>.*</\\1>",content) # 嚴謹的寫法
# print(ret)

# 4、給分組起別名(?P<name>) 寫到前面
# 5、(?P=name):引用別名爲name的分組匹配到的字符串
# 檢查html網頁的合法性
# content = "<h1><body>hello world</body></h1>"
# # ret = re.match("<(\w+)><(\w+)>.*<(/\\2)></\\1>",content)
# ret = re.match("<(?P<a>\w+)><(?P<b>\w+)>.*</(?P=b)></(?P=a)>",content)
# print(ret)

7、案例操作 [ sub() search()findall()]


import re
# 1、search
# content = "閱讀次數88次,下載次數30次"
# ret = re.search("\d+",content)
# print(ret)  # 只打印一個結果,並不能所有匹配

# # 2、findall(): 查找字符串中所有匹配的數據,返回的是列表
# # 匹配所有數字
content = "閱讀次數88次,下載次數30次"
ret = re.findall("\d+",content)
print(ret)  # 打印列表 包含所有數字


# 3、sub() :替換,返回的是替換後的字符串
# 將所有次數歸0
# content = "閱讀次數88次,下載次數30次"
# ret = re.sub("\d+","0",content)
# print(ret)  # 只打印一個結果,並不能所有匹配

8、貪婪和非貪婪

"""
Python 中默認是貪婪,總是嘗試儘可能多的匹配字符,非貪婪相反,總是儘可能少的匹配字符
"""
import re


# 1、Python 中默認是貪婪,總是嘗試儘可能多的匹配字符,非貪婪相反,總是儘可能少的匹配字符
# ret = re.match("\d{2,5}","12345")
# print(ret) # 匹配了5次

# 2、字符串前面加r“表示原生字符串”

# 3、re.complie(strPattern)
# 將字符串形式的正則表達式編譯成pattern對象

pattern = re.compile("\d{2,5}")
ret = pattern.match("12345")
print(ret)


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