python正则表达式保姆级教学

正则表达式(regex)是描述文本模式的特殊字符串,能快速定位符合规则的内容。​

它由普通字符和元字符(如*、\d)组成,可定义匹配规则。例如\w+@\w+\.\w+能直接匹配所有邮箱。​

其核心价值是高效处理文本,在数据清洗、爬虫解析等场景中,比传统方法更简洁高效。​

作为跨语言技术,正则在各编程语言中都有支持,是处理文本的实用工具。​

下面我们将详细讲讲正则表达式​

导入库re

正则表达式是标准库,直接可以导入使用,不需要下载,其库名为re

import re

正则表达式的四个常用函数

在 Python 的re模块中,有四个函数是处理文本匹配的核心工具,覆盖了大多数文本处理场景:

1. re.search ():查找首个匹配项

功能:在整个字符串中搜索第一个符合目标的内容,返回匹配对象。

示例

import re

text = "苹果,香蕉,橘子,香蕉"

result = re.search("香蕉", text)

print(result.group()) # 输出:香蕉

特点:找到第一个匹配后就停止搜索,适合提取首个目标。

2. re.findall ():获取所有匹配结果

功能:查找字符串中所有符合目标的内容,返回包含所有结果的列表。

示例

fruits = re.findall("香蕉", "苹果,香蕉,橘子,香蕉")

print(fruits) # 输出:['香蕉', '香蕉']

特点:一次性返回所有匹配项,常用于批量提取同类信息。

3. re.sub ():替换匹配内容

功能:将匹配到的内容替换为指定字符串,支持简单替换逻辑。

示例

# 用"橙子"替换"香蕉"

new_text = re.sub("香蕉", "橙子", "苹果,香蕉,橘子,香蕉")

print(new_text) # 输出:苹果,橙子,橘子,橙子

特点:能快速替换文本中的目标内容,是文本修改的常用工具。

4. re.match ():从开头匹配内容

功能:只从字符串的开头开始匹配目标内容,若开头不匹配则返回 None。

示例

# 字符串开头是"苹果",匹配成功

result1 = re.match("苹果", "苹果,香蕉,橘子")

print(result1.group()) # 输出:苹果

# 字符串开头不是"香蕉",匹配失败

result2 = re.match("香蕉", "苹果,香蕉,橘子")

print(result2) # 输出:None

特点:仅检查字符串开头是否符合目标,适合验证字符串是否以特定内容开头。

这四个函数基本能满足日常文本处理需求,掌握它们可以解决大部分简单的文本匹配问题。

一、表示字符范围

字符范围用于指定匹配的字符集合,主要通过方括号[]实现:

1. [abc]:匹配 a、b、c 中任意一个字符

  • 匹配逻辑:方括号内的任意单个字符
  • 示例代码
a='a1b2c3'
re.findall('[abc]', a)  # 输出:['a', 'b', 'c']
  • 结果分析:匹配到字符串中的 'a'、'b'、'c',跳过数字
  • 实际应用:筛选特定字符,如验证验证码是否包含指定字母

2. [a-z]:匹配任意小写字母

  • 匹配逻辑:ASCII 码范围从 97 (a) 到 122 (z) 的字符
  • 示例代码
a='A1b2C3'
re.findall('[a-z]', a)  # 输出:['b']
  • 结果分析:仅匹配到小写字母 'b',忽略大写和数字
  • 实际应用:提取文本中的英文单词

3. [0-9a-zA-Z]:匹配数字、字母

  • 匹配逻辑:组合多个字符范围
  • 示例代码
a='a1b2c3'
re.findall('[0-9a-zA-Z]',a)  # 输出:['a', '1']
  • 结果分析:匹配字母和数字,跳过特殊符号
  • 实际应用:过滤用户名中的非法字符

4. [^abc]:匹配除 a、b、c 外的任意字符

  • 匹配逻辑:方括号内^表示取反
  • 示例代码
a='a1b2c3'
re.findall('[^abc]', a)  # 输出:['1', '2', '3']
  • 结果分析:匹配所有非 a、b、c 的字符
  • 实际应用:清理文本中的干扰字符

二、表示字符串出现次数

出现次数和位置限定符用于约束匹配规则:

1. *:前面元素出现 0 次或多次

  • 匹配逻辑:贪婪匹配,尽可能多匹配
  • 示例代码
a= 'a ab abb'
re.findall('ab*',a)  # 输出:['a', 'ab', 'abb']
  • 结果分析
    • 第一个 'a':b 出现 0 次
    • 第二个 'ab':b 出现 1 次
    • 第三个 'abb':b 出现 2 次
  • 实际应用:匹配可能带后缀的固定前缀

2. +:前面元素出现 1 次或多次

  • 匹配逻辑:至少出现 1 次
  • 示例代码
a='a ab abb'
re.findall('ab+', a)  # 输出:['ab', 'abb']
  • 结果分析:跳过单独的 'a',仅匹配带 b 的情况
  • 实际应用:验证密码至少包含一个特定字符

3. ?:前面元素出现 0 次或 1 次

  • 匹配逻辑:非贪婪匹配,尽可能少匹配
  • 示例代码
a='a ab abb'
re.findall('ab?', a)  # 输出:['a', 'ab', 'ab']
  • 结果分析
    • 第一个 'a':b 出现 0 次
    • 后两个 'abb':b 出现 1 次(非贪婪截断)
  • 实际应用:处理可选参数,如 color/colour

4. {n}:前面元素恰好出现 n 次

  • 匹配逻辑:精确控制重复次数
  • 示例代码
a='aa aaa'
re.findall('a{2}', a)  # 输出:['aa', 'aa']
  • 结果分析
    • 'aa':完整匹配一次
    • 'aaa':拆分为两个连续的 'aa'
  • 实际应用:验证日期格式中的年份(如 2023)

5. {n,}:前面元素至少出现 n 次

  • 匹配逻辑:无上限的重复
  • 示例代码
a='aa aaa aaaa'
re.findall('a{2,}', a)  # 输出:['aa', 'aaa', 'aaaa']
  • 结果分析:匹配所有长度≥2 的连续 'a'
  • 实际应用:检测连续重复字符(如密码强度)

6. {n,m}:前面元素出现 n 到 m 次

  • 匹配逻辑:区间控制重复次数
  • 示例代码
a= 'aa aaa aaaa'
re.findall('a{2,3}',a)  # 输出:['aa', 'aaa', 'aaa']
  • 结果分析
    • 'aaaa' 被拆分为两个 'aaa'(优先匹配最大长度)
  • 实际应用:验证手机号长度(如 11 位)

7. ^:匹配字符串开头

  • 匹配逻辑:定位匹配位置
  • 示例代码
a='abc a123'
re.findall('^a', a)  # 输出:['a']
  • 结果分析:仅匹配第一个单词的开头 'a'
  • 实际应用:验证 URL 协议(如 ^https://)

8. $:匹配字符串结尾

  • 匹配逻辑:定位匹配位置
  • 示例代码
a='abc123 a1234'
re.findall('3$', a)  # 输出:['3']
  • 结果分析:仅匹配完全以 '3' 结尾的字符串
  • 实际应用:验证文件扩展名(如.jpg$)

三,表示同一类字符

1. \d:匹配任意数字

  • 匹配逻辑:等价于[0-9],匹配单个数字字符
  • 示例代码
a = 'a1b2c3'
re.findall(r'\d', a)  # 输出:['1', '2', '3']

  • 结果分析:从字符串中提取所有数字字符

2. \D:匹配任意非数字

  • 匹配逻辑:等价于[^0-9],匹配数字以外的任意字符
  • 示例代码
a = 'a1b2c3'
re.findall(r'\D', a)  # 输出:['a', 'b', 'c']
  • 结果分析:提取所有非数字字符,忽略数字

3. \w:匹配单词字符

  • 匹配逻辑:等价于[a-zA-Z0-9_],匹配字母、数字、下划线
  • 示例代码
a = 'a1_b@c'
re.findall(r'\w', a)  # 输出:['a', '1', '_', 'b', 'c']
  • 结果分析:保留单词字符,过滤特殊符号@

4. \W:匹配非单词字符

  • 匹配逻辑:等价于[^a-zA-Z0-9_],匹配单词字符以外的字符
  • 示例代码
a = 'a1_b@c'
re.findall(r'\W', a)  # 输出:['@']
  • 结果分析:仅提取特殊符号,忽略单词字符

5. \s:匹配空白字符

  • 匹配逻辑:匹配空格、制表符、换行符等空白字符
  • 示例代码
a = 'a b\tc\n'
re.findall(r'\s', a)  # 输出:[' ', '\t', '\n']
  • 结果分析:提取所有类型的空白字符

6. \S:匹配非空白字符

  • 匹配逻辑:匹配除空白字符外的任意字符
  • 示例代码
a = 'a b\tc\n'
re.findall(r'\S', a)  # 输出:['a', 'b', 'c']
  • 结果分析:提取所有可见字符,忽略空白

7. \b:匹配单词边界

  • 匹配逻辑:单词字符(\w)与非单词字符(\W)的交界处
  • 示例代码
a = 'cat catch copycat'
re.findall(r'\bcat\b', a)  # 输出:['cat']
  • 结果分析:仅匹配独立单词 "cat",排除 "catch" 和 "copycat" 中的 "cat"

8. \B:匹配非单词边界

  • 匹配逻辑:两个单词字符之间或两个非单词字符之间的位置
  • 示例代码
a = 'cat copycat'
re.findall(r'\Bcat\B', a)  # 输出:[]
  • 结果分析:"cat" 两侧均为单词边界,因此无匹配结果

9. .:匹配任意字符(除换行符)

  • 匹配逻辑:匹配单个任意字符,但不包括换行符\n
  • 示例代码
a = 'abc\n123'
re.findall(r'.', a)  # 输出:['a', 'b', 'c', '1', '2', '3']
  • 结果分析:换行符被忽略,仅匹配可见字符

正则表达式中的贪婪与非贪婪模式

一、贪婪模式(默认行为)

核心特点:尽可能多地匹配字符,直到无法继续匹配为止。
触发符号*+?{n,}{n,m} 等重复量词默认采用贪婪模式。

1. .*:匹配任意字符(贪婪)

a = '<div>content</div>'
re.findall(r'<.*>', a)  # 输出:['<div>content</div>']

  • 匹配逻辑
    1. < 匹配起始标签
    2. .* 贪婪地匹配所有后续字符,直到字符串末尾
    3. > 尝试匹配,但字符串已结束,回溯直到找到最后一个 >

2. \d+:匹配数字(贪婪)

a = '123abc'
re.findall(r'\d+', a)  # 输出:['123']
  • 匹配逻辑\d+ 尽可能多地匹配数字,直到遇到 a 停止。

二、非贪婪模式(懒惰模式)

核心特点:尽可能少地匹配字符,一旦满足条件就停止匹配。
触发符号:在重复量词后添加 ?,如 *?+???{n,}?{n,m}?

3. .*?:匹配任意字符(非贪婪)

a = '<div>content</div>'
re.findall(r'<.*?>', a)  # 输出:['<div>', '</div>']
  • 匹配逻辑
    1. < 匹配起始标签
    2. .*? 非贪婪地匹配最少字符,直到遇到第一个 >
    3. 立即停止匹配,继续寻找下一个匹配项

4. \d+?:匹配数字(非贪婪)

a = '123abc'
re.findall(r'\d+?', a)  # 输出:['1', '2', '3']
  • 匹配逻辑\d+? 每次只匹配一个数字,满足 + 至少一次的要求后立即停止。

三、对比与应用场景

5. 贪婪 vs 非贪婪

a = 'ababab'
re.findall(r'a.*b', a)  # 贪婪:['ababab']
re.findall(r'a.*?b', a)  # 非贪婪:['ab', 'ab', 'ab']
  • 结果分析
    • 贪婪模式:从第一个 a 开始,尽可能多地匹配,直到最后一个 b
    • 非贪婪模式:从每个 a 开始,匹配到最近的 b 即停止

6. 实际应用:提取 HTML 标签

a = '<p>First</p><p>Second</p>'
re.findall(r'<p>.*</p>', a)  # 贪婪:['<p>First</p><p>Second</p>']
re.findall(r'<p>.*?</p>', a)  # 非贪婪:['<p>First</p>', '<p>Second</p>']
  • 最佳实践:提取成对标签时,必须使用非贪婪模式避免过度匹配。

或和组

一、或操作符(|)

核心功能:匹配多个模式中的任意一个,优先级低于分组。

1. 基础语法

a = 'cat dog fish'
re.findall(r'cat|dog', a)  # 输出:['cat', 'dog']
  • 匹配逻辑:依次尝试匹配 cat 或 dog,找到即停止。

2. 跨类型匹配

a = '123 abc'
re.findall(r'\d+|abc', a)  # 输出:['123', 'abc']
  • 匹配逻辑:优先匹配连续数字,否则匹配 abc

3. 注意优先级

a = 'ab ac'
re.findall(r'a|b|c', a)  # 输出:['a', 'b', 'a', 'c'](匹配单个字符)
re.findall(r'a(b|c)', a)  # 输出:['ab', 'ac'](正确分组)
  • 最佳实践:使用 | 时建议用括号明确分组,避免优先级问题。

二、分组(Parentheses)

核心功能:将多个字符视为一个整体,并可捕获匹配结果。

4. 基础分组

a = 'abab'
re.findall(r'(ab)+', a)  # 输出:['ab']
  • 匹配逻辑:将 ab 作为一个整体重复匹配,捕获最后一次出现的 ab

5. 捕获分组

a = '2023-07-10'
re.findall(r'(\d{4})-(\d{2})-(\d{2})', a)  # 输出:[('2023', '07', '10')]
  • 提取技巧:通过索引访问分组结果(如 match.group(1) 返回 2023)。

6. 非捕获分组

a = 'abab'
re.findall(r'(?:ab)+', a)  # 输出:['abab']
  • 语法差异(?:...) 表示不捕获分组内容,仅用于分组。

7. 反向引用

a = 'hello world'
re.findall(r'(\w) \1', a)  # 输出:['l'](匹配重复字符)
  • 匹配逻辑\1 引用第一个分组内容,此处匹配两个连续相同字符。

三、组合应用

8. 分组与或结合

a = 'John Smith, Jane Doe'
re.findall(r'(John|Jane) (Smith|Doe)', a)  # 输出:[('John', 'Smith'), ('Jane', 'Doe')]
  • 匹配逻辑:匹配名和姓的任意组合。

9. 复杂分组嵌套

a = '<div class="container">Text</div>'
re.findall(r'<div(.*?)>(.*?)</div>', a)  # 输出:[(' class="container"', 'Text')]

  • 提取技巧:分组 1 捕获属性,分组 2 捕获内容。

四、注意事项

  1. 分组性能:过多嵌套分组可能影响匹配效率,非必要时使用非捕获分组。

  2. 交替顺序| 按从左到右的顺序尝试匹配,长模式应优先放置。
    示例:r'https?|ftp' 比 r'ftp|https?' 更高效。

  3. 边界处理:确保分组不遗漏必要字符。
    示例:r'(a|ab)' 应改为 r'(ab|a)' 以优先匹配更长模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值