python学习笔记12 -- 正则表达式 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 在内的任何字符请使用像 (.\d匹配一个数字字符。等价于[0-9]。\D匹配一个非数字字符。等价于[^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”。特殊字符仅有反斜线 \ 保持特殊含义用于转义字符。其它特殊字符如星号、加号、各种括号等均作为普通字符。脱字符 ^ 如果出现在首位则表示负值字符集合如果出现在字符串中间就仅作为普通字符。连字符 - 如果出现在字符串中间表示字符范围描述如果出现在首位或末尾则仅作为普通字符。右方括号应转义出现也可以作为首位字符出现。[^xyz]匹配未列出的任意字符。[a-z]字符范围。匹配在Unicode编码表指定范围内的任意字符。 例如[a-z]可以匹配“a”到“z”范围内的任意小写字母字符。2.2 数量词字符描述*****匹配前面的子表达式零次或多次。等价于 {0,}。匹配前面的子表达式一次或多次。等价于 {1,}。?匹配前面的子表达式零次或一次。等价于 {0,1}。{n}n是一个非负整数。匹配确定的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)与常规的圆括号类似但分组所匹配到了子字符串可通过符号分组名称 name 来访问。(?Pname)引用一个命名组合。\num向后引用一个子字符串该子字符串与正则表达式的第num个用括号围起来的子表达式匹配。其中num从1开始。例如(.)\1 匹配两个连续的相同字符。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 产生匹配的第一个位置并返回相应的 Match。如果字符串中没有与模式匹配的位置则返回 None。str2HelloWorldresultre.search(ro,str2)print(result,type(result))# re.Match object; span(4, 5), matcho class re.Match# 从匹配对象中提取实际匹配到的字符串内容。print(result.group())# o# 在字符串中搜索第1个数字text_one今天是2026年1月25日天气不错。patternr\d#正则表达式\d代表一位数字\d代表1位或连续的多位的数字matchre.search(pattern,text_one)print(match.group())# 在字符串中搜索第1个手机号码这里的规则是 一共11位3位-4位-4位模式text_two联系电话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(): 在整个字符串中搜索匹配。非常适合用于验证输入格式、提取特定模式的文本内容等场景。text_one2026年1月25日天气不错。patternr\dmatchre.match(pattern,text_one)ifmatch:print(match.group())else:print(不满足以数字开头的规则)贪婪匹配与非贪婪匹配**贪婪匹配默认模式尽可能匹配最长的字符串。非贪婪匹配在量词*//?/{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(): 返回所有匹配的字符串列表# 在字符串中搜索所有数字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日毕业日期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 最左边非重叠出现的 pattern 而获得的字符串。如果样式没有找到则不加改变地返回 string。repl 可以是字符串或函数如为字符串则其中任何反斜杠转义序列都会被处理。 也就是说\n 会被转换为一个换行符\r 会被转换为一个回车符依此类推。如果 repl 是一个函数则它会针对每次 pattern 的非重叠出现的情况被调用。 该函数接受单个 Match 参数并返回替换字符串。可选参数 count 是要替换的最大次数count 必须是非负整数。如果省略这个参数或设为 0所有的匹配都会被替换。str212321ASDJASLD21321sadid12321#去掉首尾的数字pattern2r^\d|\d$resultre.sub(pattern2,,str2)print(result)#去掉所有的数字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之间的数字importre# 检验数字是否在[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 提取网址importre# 获取所有href中网址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 替换文本中的所有数字为对应的词importre# 使用 re.sub() 方法将数字替换为对应的单词sentenceI have 2 apples and 3 oranges.# 定义数字到词的映射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)