
14正則表達式1 什么是正則表達式正則表達式regular expression常簡寫為regex、regexp或re是一種用于匹配和操作文本的強大工具它是由一系列字符和特殊字符組成的模式用于描述要匹配的文本模式。正則表達式可以在文本中查找、替換、提取和驗證特定的模式。體會正則的強大importre str2h1b2c3dprint(re.split(r\d,str2))# [h, b, c, d]2 正則表達式的語法組件2.1 字符類字符描述.匹配除 \r\n 之外的任何單個字符。要匹配包括 \r\n 在內(nèi)的任何字符請使用像 (.\d匹配一個數(shù)字字符。等價于[0-9]。\D匹配一個非數(shù)字字符。等價于[^0-9]。\w匹配包括下劃線的任何單詞字符。等價于[A-Za-z0-9_]注意Unicode正則表達式會匹配中文字符。\W匹配任何非單詞字符。等價于[^A-Za-z0-9_]。\s匹配任何空白字符包括空格、制表符、換頁符等。等價于[ \f\n\r\t\v]。\S匹配任何非空白字符。等價于[^ \f\n\r\t\v]。[xyz]匹配所包含的任意一個字符。如 [abc] 可以匹配“plain”中的“a”。特殊字符僅有反斜線 \ 保持特殊含義用于轉義字符。其它特殊字符如星號、加號、各種括號等均作為普通字符。脫字符 ^ 如果出現(xiàn)在首位則表示負值字符集合如果出現(xiàn)在字符串中間就僅作為普通字符。連字符 - 如果出現(xiàn)在字符串中間表示字符范圍描述如果出現(xiàn)在首位或末尾則僅作為普通字符。右方括號應轉義出現(xiàn)也可以作為首位字符出現(xiàn)。[^xyz]匹配未列出的任意字符。[a-z]字符范圍。匹配在Unicode編碼表指定范圍內(nèi)的任意字符。 例如[a-z]可以匹配“a”到“z”范圍內(nèi)的任意小寫字母字符。2.2 數(shù)量詞字符描述*****匹配前面的子表達式零次或多次。等價于 {0,}。匹配前面的子表達式一次或多次。等價于 {1,}。?匹配前面的子表達式零次或一次。等價于 {0,1}。{n}n是一個非負整數(shù)。匹配確定的n次。例如 o{2} 不能匹配“Bob”中的“o”但是能匹配“food”中的兩個“o”。{n,}至少匹配n次。{n,m}其中nm。最少匹配n次且最多匹配m次。?非貪心量化當該字符緊跟在任何一個其他重復修飾符*?{n}{n,}{n,m}后面時匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串而默認的貪婪模式則盡可能多的匹配所搜索的字符串。例如對于字符串“oooo”o? 將匹配單個“o”而 o 將匹配所有“o”。2.3 邊界匹配器字符描述^匹配字符串的開始位置。$匹配字符串的結束位置。\b匹配一個單詞邊界也就是指單詞和空格間的位置。\B匹配非單詞邊界。2.4 匹配分組字符描述x|y匹配 x 或 y(pattern)匹配 pattern 并獲取這一匹配的子字符串。(?P pattern)與常規(guī)的圓括號類似但分組所匹配到了子字符串可通過符號分組名稱 name 來訪問。(?Pname)引用一個命名組合。\num向后引用一個子字符串該子字符串與正則表達式的第num個用括號圍起來的子表達式匹配。其中num從1開始。例如(.)\1 匹配兩個連續(xù)的相同字符。2.5 元字符注意. ^ $ * ? { } [ ] \ | ( )屬于元字符[ 和 ]這兩個元字符用于指定一個字符類也就是你希望匹配的字符的一個集合。元字符(除了 \)在字符類中是不起作用的。 例如[akm] 將會匹配以下任一字 符 ′ a ′ , ′ k ′ , ′ m ′ 或 ′ ] 將會匹配以下任一字符 a, k, m 或 ]將會匹配以下任一字符′a′,′k′,′m′或′‘’$’ 通常是一個元字符但在一個字符類中它的特殊性被消除了。3 原始字符串Python中字符串前面加上 r 表示原始字符串忽略轉義。原始字符串非常適合用于正則表達式因為正則表達式中通常包含很多反斜杠例如 \d 或 \w使用原始字符串可以避免反斜杠帶來的轉義問題。例如strHello\nWorldHello WorldstrrHello\nWorldHello\nWorld4 re模塊Python的re模塊提供了正則表達式匹配操作。re模塊中提供了一些方法用于查找或處理字符串。4.1 search方法re.search(pattern, string, flags)掃描整個 string 查找正則表達式 pattern 產(chǎn)生匹配的第一個位置并返回相應的 Match。如果字符串中沒有與模式匹配的位置則返回 None。str2HelloWorldresultre.search(ro,str2)print(result,type(result))# re.Match object; span(4, 5), matcho class re.Match# 從匹配對象中提取實際匹配到的字符串內(nèi)容。print(result.group())# o# 在字符串中搜索第1個數(shù)字text_one今天是2026年1月25日天氣不錯。patternr\d#正則表達式\d代表一位數(shù)字\d代表1位或連續(xù)的多位的數(shù)字matchre.search(pattern,text_one)print(match.group())# 在字符串中搜索第1個手機號碼這里的規(guī)則是 一共11位3位-4位-4位模式text_two聯(lián)系電話138-1234-5678備用號碼159-8765-4321# pattern r\d{3}-\d{4}-\d{4}# match re.search(pattern,text_two)# print(match.group())## pattern2 r(\d{3})-(\d{4})-(\d{4}) #這里把正則表達式分為3個組組號依次是從左往右遇到(組號1# match2 re.search(pattern2,text_two)# print(match2.group())# print(match2.group(1))# print(match2.group(2))# print(match2.group(3))pattern3r((\d{3})-(\d{4})-(\d{4}))#這里把正則表達式分為4個組組號依次是從左往右遇到(組號1match3re.search(pattern3,text_two)print(match3.group())print(match3.group(1))print(match3.group(2))print(match3.group(3))print(match3.group(4))4.2 matchre.match(pattern, string, flags)如果 string 開頭的零個或多個字符與正則表達式 pattern 匹配則返回相應的 Match。如果字符串與模式不匹配則返回 None。re.match(): 僅從字符串開頭開始匹配。適合用于驗證字符串開頭是否符合特定格式。re.search(): 在整個字符串中搜索匹配。非常適合用于驗證輸入格式、提取特定模式的文本內(nèi)容等場景。text_one2026年1月25日天氣不錯。patternr\dmatchre.match(pattern,text_one)ifmatch:print(match.group())else:print(不滿足以數(shù)字開頭的規(guī)則)貪婪匹配與非貪婪匹配**貪婪匹配默認模式盡可能匹配最長的字符串。非貪婪匹配在量詞*//?/{n,m}后加?盡可能匹配最短的字符串。示例textaabbaabb# 貪婪匹配默認盡可能長print(re.search(ra.*b,text).group())# 輸出aabbaabb# 非貪婪匹配盡可能短print(re.search(ra.*?b,text).group())# 輸出aab4.3 findallre.findall(pattern, string, flags)返回 pattern 在 string 中的所有非重疊匹配以字符串列表或字符串元組列表的形式。對 string 的掃描從左至右匹配結果按照找到的順序返回。空匹配也包括在結果中。re.search(): 返回第一個匹配的 Match 對象re.match(): 從字符串開頭開始匹配返回第一個匹配的 Match 對象re.findall(): 返回所有匹配的字符串列表# 在字符串中搜索所有數(shù)字text_one今天是2026年1月25日天氣不錯。patternr\dresultsre.findall(pattern,text_one)# print(results) #[2, 0, 2, 6, 1, 2, 5]pattern2r\dresults2re.findall(pattern2,text_one)# print(results2) #[2026, 1, 25]# 在字符串中匹配所有日期text_two出生日期2002年5月6日畢業(yè)日期2025-07-1入職日期2026/3/8pattern3r\d{4}[年/-]\d{1,2}[月/-]\d{1,2}日?results3re.findall(pattern4,text_two)print(results4)4.4 subre.sub(pattern, repl, string, count0)返回通過使用 repl 替換在 string 最左邊非重疊出現(xiàn)的 pattern 而獲得的字符串。如果樣式?jīng)]有找到則不加改變地返回 string。repl 可以是字符串或函數(shù)如為字符串則其中任何反斜杠轉義序列都會被處理。 也就是說\n 會被轉換為一個換行符\r 會被轉換為一個回車符依此類推。如果 repl 是一個函數(shù)則它會針對每次 pattern 的非重疊出現(xiàn)的情況被調(diào)用。 該函數(shù)接受單個 Match 參數(shù)并返回替換字符串??蛇x參數(shù) count 是要替換的最大次數(shù)count 必須是非負整數(shù)。如果省略這個參數(shù)或設為 0所有的匹配都會被替換。str212321ASDJASLD21321sadid12321#去掉首尾的數(shù)字pattern2r^\d|\d$resultre.sub(pattern2,,str2)print(result)#去掉所有的數(shù)字pattern2r\dresultre.sub(pattern2,,str2)print(result)4.5 splitre.split(pattern, string, maxsplit0)用 pattern 分開 string 。 如果在 pattern 中捕獲到括號那么所有的組里的文字也會包含在列表里。如果 maxsplit 非零 最多進行 maxsplit 次分隔 剩下的字符全部返回到列表的最后一個元素。str2h1b22c33dprint(re.split(r\d,str2))# [h, b, c, d]5 案例5.1 校驗手機號碼importre# 校驗手機號碼tel_numbers[13812345678,# 合法11456817239,# 非法19912345678,# 合法17138412356,# 合法12345678908,# 非法14752345673,# 合法1800123456,# 非法]patternr^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$foriintel_numbers:print(f{i:20}{合法 if re.match(pattern, i) else 非法})5.2 校驗郵箱importre# 校驗郵箱的合法性email_addresses[exampleexample.com,# 合法user.namesubdomain.example.cn,# 合法username.com,# 非法missingusername.com,# 非法-dasdqq.com,# 合法]# pattern r[\w!#$%*-/?^{|}~.][\w!#$%*-/?^{|}~.]\.[a-zA-Z]{2,}$patternr^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$foriinemail_addresses:print(f{i:40}{合法 if re.match(pattern, i) else 非法})5.3 校驗0-255之間的數(shù)字importre# 檢驗數(shù)字是否在[0,255]范圍numbers[0,9,50,100,199,200,255,256,-1,01,001]# 十位為1-9?表示可以沒有十位個位是0-9# 或 百位是1十位是0-9個位是0-9# 或 百位是2十位是0-4個位是0-9# 或 百位是2十位是5個位是0-5patternr^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])$fornuminnumbers:print(f{num:5}{合法 if re.match(pattern, num) else 非法})5.4 提取網(wǎng)址importre# 獲取所有href中網(wǎng)址htmllink relalternate hreflangzh hrefhttps://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangzh-Hans hrefhttps://zh.wikipedia.org/zh-hans/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangzh-Hans-CN hrefhttps://zh.wikipedia.org/zh-cn/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangzh-Hans-MY hrefhttps://zh.wikipedia.org/zh-my/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangzh-Hans-SG hrefhttps://zh.wikipedia.org/zh-sg/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangzh-Hant hrefhttps://zh.wikipedia.org/zh-hant/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangzh-Hant-HK hrefhttps://zh.wikipedia.org/zh-hk/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangzh-Hant-MO hrefhttps://zh.wikipedia.org/zh-mo/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangzh-Hant-TW hrefhttps://zh.wikipedia.org/zh-tw/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F link relalternate hreflangx-default hrefhttps://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8Fpatternrhref\(.)\forurlinre.findall(pattern,html):print(url)5.5 替換文本中的所有數(shù)字為對應的詞importre# 使用 re.sub() 方法將數(shù)字替換為對應的單詞sentenceI have 2 apples and 3 oranges.# 定義數(shù)字到詞的映射num_map{1:one,2:two,3:three,4:four,5:five}print(re.sub(r(\d),lambdax:num_map[x[0]],sentence))# I have two apples and three oranges.defdigit_to_word(match):print(match,match[0])num_map{1:one,2:two,3:three,4:four,5:five}returnnum_map[match[0]]# 或者 match.group(0)sentenceI have 2 apples and 3 oranges.resultre.sub(r\d,digit_to_word,sentence)