Python 第二十节 正则表达式使用详解及注意事项

Python 中正则表达式使用方法match、search、findall、finditer等常用方法介绍,及案例分析

1. 正则表达式基础

导入模块

python 复制代码
    import re

基本匹配方法

1.1. re.match() - 从字符串开头匹配

python 复制代码
    pattern = r"hello"
    text = "hello world"

    result = re.match(pattern, text)
    if result:
        print("匹配成功:", result.group())  # 输出: hello
    else:
        print("匹配失败")

1.2. re.search() - 搜索整个字符串

python 复制代码
    pattern = r"world"
    text = "hello world"

    result = re.search(pattern, text)
    if result:
        print("找到:", result.group())  # 输出: world
        print("位置:", result.span())   # 输出: (6, 11)

1.3. re.findall() - 查找所有匹配

python 复制代码
    pattern = r"\d+"  # 匹配一个或多个数字
    text = "我有3个苹果和5个香蕉"

    results = re.findall(pattern, text)
    print(results)  # 输出: ['3', '5']

1.4. re.finditer() - 返回迭代器

python 复制代码
    pattern = r"\w+"
    text = "hello world python"

    for match in re.finditer(pattern, text):
        print(f"找到: '{match.group()}' 位置: {match.span()}")

1.5. re.sub() - 替换匹配内容

python 复制代码
    pattern = r"苹果"
    text = "我喜欢吃苹果"
    new_text = re.sub(pattern, "香蕉", text)
    print(new_text)  # 输出: 我喜欢吃香蕉

1.6. re.split() - 根据模式分割字符串

python 复制代码
    pattern = r"\s+"  # 一个或多个空白字符
    text = "hello   world   python"
    parts = re.split(pattern, text)
    print(parts)  # 输出: ['hello', 'world', 'python']

2. 正则表达式语法详解

常用元字符

python 复制代码
    # 字符类
    text = "abc123 def"
    print(re.findall(r"[a-z]", text))      # 所有小写字母: ['a', 'b', 'c', 'd', 'e', 'f']
    print(re.findall(r"[0-9]", text))      # 所有数字: ['1', '2', '3']
    print(re.findall(r"[^0-9]", text))     # 非数字: ['a', 'b', 'c', ' ', 'd', 'e', 'f']

    # 预定义字符类
    print(re.findall(r"\d", text))         # 数字: ['1', '2', '3']
    print(re.findall(r"\D", text))         # 非数字: ['a', 'b', 'c', ' ', 'd', 'e', 'f']
    print(re.findall(r"\w", text))         # 单词字符: ['a', 'b', 'c', '1', '2', '3', 'd', 'e', 'f']
    print(re.findall(r"\W", text))         # 非单词字符: [' ']
    print(re.findall(r"\s", text))         # 空白字符: [' ']

量词

python 复制代码
    text = "a ab abb abbb abbbb"

    print(re.findall(r"ab?", text))    # a后跟0或1个b: ['a', 'ab', 'ab', 'ab', 'ab']
    print(re.findall(r"ab+", text))    # a后跟1个或多个b: ['ab', 'abb', 'abbb', 'abbbb']
    print(re.findall(r"ab*", text))    # a后跟0个或多个b: ['a', 'ab', 'abb', 'abbb', 'abbbb']
    print(re.findall(r"ab{2}", text))  # a后跟2个b: ['abb']
    print(re.findall(r"ab{2,3}", text)) # a后跟2-3个b: ['abb', 'abbb']

位置锚点

python 复制代码
    text = "hello world"

    print(re.search(r"^hello", text))    # 匹配开头
    print(re.search(r"world$", text))    # 匹配结尾
    print(re.search(r"\bworld\b", text)) # 单词边界

分组

python 复制代码
    text = "2023-12-25"

    # 捕获分组
    match = re.search(r"(\d{4})-(\d{2})-(\d{2})", text)
    if match:
        print("完整匹配:", match.group(0))  # 2023-12-25
        print("年:", match.group(1))       # 2023
        print("月:", match.group(2))       # 12
        print("日:", match.group(3))       # 25
        print("所有分组:", match.groups())  # ('2023', '12', '25')

    # 非捕获分组 (?:...)
    match = re.search(r"(?:\d{4})-(\d{2})-(\d{2})", text)
    print(match.groups())  # 只有月和日: ('12', '25')

3. 实用案例

3.1: 邮箱验证

python 复制代码
    def validate_email(email):
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return bool(re.match(pattern, email))

    emails = ["test@example.com", "invalid.email", "name@domain.co.uk"]
    for email in emails:
        print(f"{email}: {'有效' if validate_email(email) else '无效'}")

3.2: 提取手机号码

python 复制代码
    def extract_phones(text):
        # 匹配11位手机号
        pattern = r'1[3-9]\d{9}'
        return re.findall(pattern, text)

    text = "联系电话: 13812345678, 13987654321,其他号码: 15011112222"
    phones = extract_phones(text)
    print("找到的手机号:", phones)

3.3: HTML标签处理

python 复制代码
    def remove_html_tags(html):
        # 移除HTML标签
        pattern = r'<[^>]+>'
        return re.sub(pattern, '', html)

    html = "<div><p>这是一个段落</p><br></div>"
    clean_text = remove_html_tags(html)
    print("清理后:", clean_text)

3.4: 密码强度验证

python 复制代码
    def check_password_strength(password):
        if len(password) < 8:
            return "弱: 密码长度至少8位"
        
        checks = [
            (r'[A-Z]', "大写字母"),
            (r'[a-z]', "小写字母"), 
            (r'[0-9]', "数字"),
            (r'[^A-Za-z0-9]', "特殊字符")
        ]
        
        strength = 0
        missing = []
        for pattern, desc in checks:
            if re.search(pattern, password):
                strength += 1
            else:
                missing.append(desc)
        
        if strength == 4:
            return "强"
        elif strength == 3:
            return f"中 - 缺少: {', '.join(missing)}"
        else:
            return f"弱 - 缺少: {', '.join(missing)}"

    passwords = ["abc", "abcdefgh", "Abc123!", "StrongPass123!"]
    for pwd in passwords:
        print(f"'{pwd}': {check_password_strength(pwd)}")

3.5: 数据清洗

python 复制代码
    def clean_data(text):
        # 移除多余空格
        text = re.sub(r'\s+', ' ', text)
        # 移除特殊字符,只保留中文、英文、数字和常见标点
        text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s.,!?;:]', '', text)
        return text.strip()

    dirty_text = "  这是一段  需要清理的文本!!包含@#特殊字符...  "
    clean_text = clean_data(dirty_text)
    print(f"清理前: '{dirty_text}'")
    print(f"清理后: '{clean_text}'")

4. 高级技巧与注意事项

编译正则表达式(提高性能)

python 复制代码
    # 对于需要多次使用的模式,先编译
    pattern = re.compile(r'\d{3}-\d{3}-\d{4}')  # 电话号码模式

    texts = ["电话: 123-456-7890", "另一个: 111-222-3333"]
    for text in texts:
        match = pattern.search(text)
        if match:
            print("找到电话:", match.group())

使用原始字符串

python 复制代码
    # 推荐使用原始字符串,避免转义问题
    good_pattern = r"\d+\\.\d+"  # 匹配数字.数字
    bad_pattern = "\d+\\.\d+"    # 不推荐,需要双重转义

贪婪 vs 非贪婪匹配

python 复制代码
    text = "<div>内容1</div><div>内容2</div>"

    # 贪婪匹配(默认)
    greedy = re.findall(r'<div>.*</div>', text)
    print("贪婪匹配:", greedy)  # ['<div>内容1</div><div>内容2</div>']

    # 非贪婪匹配
    non_greedy = re.findall(r'<div>.*?</div>', text)
    print("非贪婪匹配:", non_greedy)  # ['<div>内容1</div>', '<div>内容2</div>']

使用标志位

python 复制代码
    text = "Hello\nWORLD\nPython"

    # 忽略大小写
    print(re.findall(r'hello', text, re.IGNORECASE))  # ['Hello']

    # 多行模式
    print(re.findall(r'^[A-Z]+', text, re.MULTILINE))  # ['H', 'WORLD', 'P']

    # 点号匹配所有字符(包括换行符)
    print(re.findall(r'.+', text, re.DOTALL))  # ['Hello\nWORLD\nPython']

5. 常见错误与调试技巧

常见错误

python 复制代码
    # 1. 忘记转义特殊字符
    text = "1.5"
    # wrong = re.findall(r"1.5", text)  # 会匹配 1任意字符5
    correct = re.findall(r"1\.5", text)  # 正确转义

    # 2. 过度复杂的正则表达式
    # 尽量保持简单,复杂的匹配可以分步进行

    # 3. 性能问题
    # 避免使用嵌套量词和过于宽泛的匹配

调试技巧

python 复制代码
    def debug_regex(pattern, text):
        print(f"模式: {pattern}")
        print(f"文本: {text}")
        
        try:
            matches = list(re.finditer(pattern, text))
            if matches:
                for i, match in enumerate(matches):
                    print(f"匹配 {i+1}: '{match.group()}' 位置: {match.span()}")
                    if match.groups():
                        print(f"  分组: {match.groups()}")
            else:
                print("没有找到匹配")
        except re.error as e:
            print(f"正则表达式错误: {e}")

    # 调试示例
    debug_regex(r'(\d+)-([a-z]+)', "123-abc 456-def")

6. 最佳实践总结

  1. 使用原始字符串 :总是使用 r"pattern" 格式
  2. 编译常用模式:重复使用的正则表达式应该编译
  3. 保持简单:复杂的匹配可以分解为多个简单的正则表达式
  4. 测试充分:使用各种边界情况进行测试
  5. 考虑性能:避免回溯灾难,使用非贪婪匹配适当
  6. 添加注释:复杂的正则表达式要添加注释说明
python 复制代码
    # 好的实践示例
    import re

    # 编译常用模式
    EMAIL_PATTERN = re.compile(
        r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    )

    def validate_emails(emails):
        """验证邮箱列表"""
        valid_emails = []
        for email in emails:
            if EMAIL_PATTERN.match(email):
                valid_emails.append(email)
        return valid_emails

    # 使用示例
    emails = ["user@example.com", "invalid", "test@domain.org"]
    print("有效邮箱:", validate_emails(emails))

掌握这些正则表达式技巧将极大提高你在Python中处理文本数据的能力!

相关推荐
新子y4 小时前
【小白笔记】「while」在程序语言中的角色
笔记·python
java1234_小锋4 小时前
[免费]基于Python的YOLO深度学习垃圾分类目标检测系统【论文+源码】
python·深度学习·yolo·垃圾分类·垃圾分类检测
野犬寒鸦4 小时前
从零起步学习MySQL || 第十章:深入了解B+树及B+树的性能优势(结合底层数据结构与数据库设计深度解析)
java·数据库·后端·mysql·1024程序员节
凌晨一点的秃头猪4 小时前
面向对象和面向过程 编程思想
python
好好好起个名真难5 小时前
正则表达式
正则表达式
总有刁民想爱朕ha5 小时前
银河麒麟v10批量部署Python Flask项目小白教程
开发语言·python·flask·银河麒麟v10
Python×CATIA工业智造6 小时前
Python函数包装技术详解:从基础装饰器到高级应用
python·pycharm
R.lin6 小时前
OSS服务模块-基于数据库配置的Java OSS服务解决方案,支持MinIO、七牛云、阿里云和腾讯云
java·数据库·后端·mysql
橄榄熊6 小时前
使用VScode 插件,连接MySQL,可视化操作数据库
数据库·mysql