python 正则表达式

python 正则表达式

一、匹配函数

1.1、re.match()

从字符串开头匹配模式,如果开头不匹配则返回None。

复制代码
import re
# 示例1:匹配成功
result = re.match(r'hello', 'hello world')
print(result.group())  # 输出: hello

# 示例2:匹配失败(开头不匹配)
result = re.match(r'world', 'hello world')
print(result)  # 输出: None

1.2、re.search()

扫描整个字符串查找第一个匹配项。

复制代码
# 示例1:查找第一个数字
result = re.search(r'\d+', 'abc 123 def 456')
print(result.group())  # 输出: 123

# 示例2:查找单词
result = re.search(r'world', 'hello world')
print(result.group())  # 输出: world

1.3、re.findall()

返回所有匹配项的列表。

复制代码
# 示例1:查找所有数字
result = re.findall(r'\d+', 'abc 123 def 456')
print(result)  # 输出: ['123', '456']

# 示例2:查找所有单词
result = re.findall(r'\w+', 'hello world, python!')
print(result)  # 输出: ['hello', 'world', 'python']

1.4、re.finditer()

返回一个迭代器,包含所有匹配的Match对象。

复制代码
# 示例
matches = re.finditer(r'\d+', 'abc 123 def 456')
for match in matches:
    print(match.group())
# 输出:
# 123
# 456

1.5、re.fullmatch()

整个字符串必须完全匹配模式。

复制代码
# 示例1:完全匹配
result = re.fullmatch(r'hello world', 'hello world')
print(result.group())  # 输出: hello world

# 示例2:不完全匹配
result = re.fullmatch(r'hello', 'hello world')
print(result)  # 输出: None

二、基础匹配

2.1、普通字符匹配

直接匹配字符本身。

复制代码
# 示例
result = re.search(r'python', 'I love python programming')
print(result.group())  # 输出: python

2.2、特殊字符匹配

使用反斜杠转义特殊字符。

复制代码
# 示例1:匹配点号
result = re.search(r'\.', 'example.com')
print(result.group())  # 输出: .

# 示例2:匹配美元符号
result = re.search(r'\$100', 'Price: $100')
print(result.group())  # 输出: $100

2.3、字符类

使用方括号定义字符集。

复制代码
# 示例1:匹配元音字母
result = re.findall(r'[aeiou]', 'hello world')
print(result)  # 输出: ['e', 'o', 'o']

# 示例2:匹配数字或字母
result = re.search(r'[0-9a-zA-Z]', '#abc123!')
print(result.group())  # 输出: a

三、重复次数

3.1、* :0次或多次

复制代码
# 示例
result = re.findall(r'ab*c', 'ac abc abbc abbbc')
print(result)  # 输出: ['ac', 'abc', 'abbc', 'abbbc']

3.2、+ :1次或多次

复制代码
# 示例
result = re.findall(r'ab+c', 'ac abc abbc abbbc')
print(result)  # 输出: ['abc', 'abbc', 'abbbc']

3.3、? :0次或1次

复制代码
# 示例
result = re.findall(r'ab?c', 'ac abc abbc')
print(result)  # 输出: ['ac', 'abc']

3.4、{n} :精确n次

复制代码
# 示例
result = re.findall(r'ab{2}c', 'abc abbc abbbc')
print(result)  # 输出: ['abbc']

3.5、{n,}:至少n次

复制代码
# 示例
result = re.findall(r'ab{2,}c', 'abc abbc abbbc abbbbc')
print(result)  # 输出: ['abbc', 'abbbc', 'abbbbc']

3.6、{n,m}:n到m次

复制代码
# 示例
result = re.findall(r'ab{1,3}c', 'abc abbc abbbc abbbbc')
print(result)  # 输出: ['abc', 'abbc', 'abbbc']

四、分组与引用

4.1、基本分组()

复制代码
# 示例
result = re.search(r'(\d{3})-(\d{4})', 'Phone: 123-4567')
print(result.group())    # 输出: 123-4567
print(result.group(1))  # 输出: 123
print(result.group(2))  # 输出: 4567

4.2、非捕获分组(?:)

复制代码
# 示例
result = re.search(r'(?:\d{3})-(\d{4})', 'Phone: 123-4567')
print(result.groups())  # 输出: ('4567',) 只有第二个分组被捕获

4.3、命名分组(?P)

复制代码
# 示例
result = re.search(r'(?P<area>\d{3})-(?P<number>\d{4})', 'Phone: 123-4567')
print(result.groupdict())  # 输出: {'area': '123', 'number': '4567'}

4.4、反向引用

复制代码
# 示例1:匹配重复单词
result = re.search(r'(\b\w+\b)\s+\1', 'hello hello world')
print(result.group())  # 输出: hello hello

# 示例2:命名分组的反向引用
result = re.search(r'(?P<word>\b\w+\b)\s+(?P=word)', 'hello hello world')
print(result.group())  # 输出: hello hello

五、特殊字符

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

复制代码
# 示例
result = re.findall(r'a.b', 'aab abb a b acb a\nb')
print(result)  # 输出: ['aab', 'abb', 'acb']

5.2、^ :匹配字符串开头

复制代码
# 示例
result = re.findall(r'^hello', 'hello world\nhello python')
print(result)  # 输出: ['hello']

5.3、$ :匹配字符串结尾

复制代码
# 示例
result = re.findall(r'python$', 'hello world\nhello python')
print(result)  # 输出: ['python']

5.4、\d :匹配数字

复制代码
# 示例
result = re.findall(r'\d+', 'abc 123 def 456')
print(result)  # 输出: ['123', '456']

5.5、\D :匹配非数字

复制代码
# 示例
result = re.findall(r'\D+', 'abc 123 def 456')
print(result)  # 输出: ['abc ', ' def ']

5.6、\s :匹配空白字符

复制代码
# 示例
result = re.findall(r'\s+', 'hello\tworld\npython')
print(result)  # 输出: ['\t', '\n']

5.7、\S :匹配非空白字符

复制代码
# 示例
result = re.findall(r'\S+', 'hello\tworld\npython')
print(result)  # 输出: ['hello', 'world', 'python']

5.8、\w :匹配单词字符(字母、数字、下划线)

复制代码
# 示例
result = re.findall(r'\w+', 'hello_world 123! python')
print(result)  # 输出: ['hello_world', '123', 'python']

5.9、\W :匹配非单词字符

复制代码
# 示例
result = re.findall(r'\W+', 'hello_world 123! python')
print(result)  # 输出: [' ', '! ']

六、贪婪与非贪婪

6.1、贪婪匹配(默认)

复制代码
# 示例
result = re.search(r'<.*>', '<html><head><title>Title</title></head></html>')
print(result.group())  # 输出: <html><head><title>Title</title></head></html>
6.2 非贪婪匹配 ?
# 示例
result = re.search(r'<.*?>', '<html><head><title>Title</title></head></html>')
print(result.group())  # 输出: <html>
6.3 贪婪与非贪婪对比
# 贪婪匹配
"""
贪婪匹配 (Greedy Matching)
定义:正则表达式默认是贪婪模式,会尽可能多地匹配字符

表示方式:*, +, ?, {n,m} 等量词默认都是贪婪的

工作原理:匹配引擎会尽可能多地匹配字符,然后根据需要进行回溯
"""
result = re.findall(r'a.*b', 'aab abb a b acb')
print(result)  # 输出: ['aab abb a b acb']


"""
解释:

< 匹配第一个 < 字符

.* 贪婪地匹配尽可能多的字符,直到字符串末尾

然后从字符串末尾回溯,寻找可以匹配 > 的位置

最终匹配到整个字符串的最后一个 >,因此匹配了整个字符串

"""


# 非贪婪匹配
"""
非贪婪匹配 (Lazy/Non-greedy Matching)
定义:在量词后加 ? 使其变为非贪婪模式,会尽可能少地匹配字符

表示方式:*?, +?, ??, {n,m}? 等

工作原理:匹配引擎会尽可能少地匹配字符,一旦满足条件就停止
"""
result = re.findall(r'a.*?b', 'aab abb a b acb')
print(result)  # 输出: ['aab', 'abb', 'a b', 'acb']

"""
解释:

< 匹配第一个 < 字符

.*? 非贪婪地匹配尽可能少的字符

遇到第一个 > 就立即停止匹配

因此只匹配到第一个标签 <html>

"""

七、替换与分割

7.1 re.sub() - 替换

复制代码
# 示例1:简单替换
result = re.sub(r'\d+', 'NUM', 'abc 123 def 456')
print(result)  # 输出: abc NUM def NUM

# 示例2:使用函数处理匹配项
def double(match):
    return str(int(match.group()) * 2)

result = re.sub(r'\d+', double, 'abc 123 def 456')
print(result)  # 输出: abc 246 def 912

7.2 re.subn() - 替换并返回替换次数

复制代码
# 示例
result, count = re.subn(r'\d+', 'NUM', 'abc 123 def 456')
print(result)  # 输出: abc NUM def NUM
print(count)  # 输出: 2
7.3 re.split() - 分割字符串
# 示例1:简单分割
result = re.split(r'\s+', 'hello   world\tpython')
print(result)  # 输出: ['hello', 'world', 'python']

# 示例2:保留分隔符
result = re.split(r'(\s+)', 'hello   world\tpython')
print(result)  # 输出: ['hello', '   ', 'world', '\t', 'python']

八、正则编译

8.1 re.compile() - 预编译正则表达式

复制代码
# 示例
pattern = re.compile(r'\d{3}-\d{4}')

# 多次使用编译后的模式
result1 = pattern.search('Phone: 123-4567')
result2 = pattern.search('Another: 789-0123')

print(result1.group())  # 输出: 123-4567
print(result2.group())  # 输出: 789-0123

九、常用匹配模式

9.1、re.IGNORECASE (re.I) - 忽略大小写

复制代码
# 示例
result = re.findall(r'python', 'Python PYTHON python', flags=re.IGNORECASE)
print(result)  # 输出: ['Python', 'PYTHON', 'python']

9.2 re.MULTILINE (re.M) - 多行模式

复制代码
# 示例
text = """first line
second line
third line"""

# 不使用多行模式
result = re.findall(r'^\w+', text)
print(result)  # 输出: ['first']

# 使用多行模式
result = re.findall(r'^\w+', text, flags=re.MULTILINE)
print(result)  # 输出: ['first', 'second', 'third']

9.3 re.DOTALL (re.S) - 点号匹配所有字符(包括换行符)

复制代码
# 示例
text = """start
end"""

# 不使用DOTALL
result = re.search(r'start.*end', text)
print(result)  # 输出: None

# 使用DOTALL
result = re.search(r'start.*end', text, flags=re.DOTALL)
print(result.group())  # 输出: start\nend

9.4 re.VERBOSE (re.X) - 详细模式(允许添加注释和空白)

复制代码
# 示例
pattern = re.compile(r"""
    \d{3}    # 区号
    -        # 分隔符
    \d{4}    # 号码
""", flags=re.VERBOSE)

result = pattern.search('Phone: 123-4567')
print(result.group())  # 输出: 123-4567

9.5 组合多个标志

复制代码
# 示例
text = """First line
second line
THIRD line"""

# 组合IGNORECASE和MULTILINE
result = re.findall(r'^[a-z]+\s', text, flags=re.I | re.M)
print(result)  # 输出: ['First ', 'second ', 'THIRD ']

十、综合例子

10.1、提取和验证电子邮件地址

复制代码
import re

# 电子邮件正则表达式
email_pattern = r"""
    ^                   # 字符串开始
    [a-zA-Z0-9._%+-]+   # 用户名部分(字母、数字、点、下划线等)
    @                  # @符号
    [a-zA-Z0-9.-]+      # 域名部分
    \.                 # 点号
    [a-zA-Z]{2,}        # 顶级域名(至少2个字母)
    $                   # 字符串结束
"""

# 编译正则表达式,使用VERBOSE模式允许注释和空白
email_regex = re.compile(email_pattern, flags=re.VERBOSE)

# 测试数据
emails = [
    "user@example.com",
    "first.last@sub.domain.co.uk",
    "invalid.email@",
    "no_at_symbol.com",
    "user@123.123.123.123",
    "user+tag@example.org"
]

# 验证和提取
print("电子邮件验证结果:")
for email in emails:
    if email_regex.fullmatch(email):
        print(f"✅ 有效: {email}")
        # 提取用户名和域名
        match = email_regex.match(email)
        username = email.split('@')[0]
        domain = email.split('@')[1]
        print(f"   用户名: {username}, 域名: {domain}")
    else:
        print(f"❌ 无效: {email}")

# 从文本中提取电子邮件
text = "联系我: john.doe@example.com 或 support@company.co.uk 获取帮助"
found_emails = email_regex.findall(text)
print("\n从文本中提取的电子邮件:", found_emails)

10.2、示例2:解析和提取URL信息

复制代码
import re

# URL解析正则表达式
url_pattern = r"""
    ^(https?://)        # 协议 (http:// 或 https://)
    ([\w.-]+)          # 域名
    (:\d+)?            # 端口 (可选)
    (/[\w./?-]*)?      # 路径 (可选)
    (\?[\w&=]*)?       # 查询字符串 (可选)
    (#[\w-]*)?         # 片段标识 (可选)
    $
"""

url_regex = re.compile(url_pattern, flags=re.VERBOSE)

# 测试URLs
urls = [
    "https://www.example.com",
    "http://sub.domain.co.uk:8080/path/to/page?query=string#section",
    "ftp://invalid.protocol.com",
    "www.missing.protocol.com",
    "https://api.service.com/v1/users?id=123&sort=desc"
]

print("\nURL解析结果:")
for url in urls:
    match = url_regex.match(url)
    if match:
        print(f"✅ 有效URL: {url}")
        print("   协议:", match.group(1))
        print("   域名:", match.group(2))
        print("   端口:", match.group(3) if match.group(3) else "默认")
        print("   路径:", match.group(4) if match.group(4) else "/")
        print("   查询:", match.group(5) if match.group(5) else "无")
        print("   片段:", match.group(6) if match.group(6) else "无")
    else:
        print(f"❌ 无效URL: {url}")

# 从HTML中提取所有链接
html_text = """
<html>
<a href="https://main.site.com">首页</a>
<a href="/about">关于我们</a>
<img src="https://cdn.site.com/images/logo.png">
<script src="/static/js/app.js"></script>
"""

link_pattern = r'(?:href|src)="([^"]*)"'
links = re.findall(link_pattern, html_text)
print("\n从HTML提取的链接:", links)

10.3、示例3:日志文件分析

复制代码
import re
from collections import defaultdict

# 日志格式示例: 127.0.0.1 - - [10/Oct/2023:13:55:36 +0800] "GET /api/user HTTP/1.1" 200 1234
log_pattern = r"""
    ^(\S+)                      # IP地址
    \s+\S+\s+\S+                # 远程登录名和用户
    \s+\[([^]]+)\]              # 时间戳
    \s+"(\S+)\s+(\S+)\s+(\S+)"  # 请求方法、路径和协议
    \s+(\d+)                    # 状态码
    \s+(\d+)                    # 响应大小
"""

log_regex = re.compile(log_pattern, flags=re.VERBOSE)

# 示例日志数据
log_entries = [
    '127.0.0.1 - - [10/Oct/2023:13:55:36 +0800] "GET /api/user HTTP/1.1" 200 1234',
    '192.168.1.1 - - [10/Oct/2023:13:56:12 +0800] "POST /api/login HTTP/1.1" 201 567',
    '10.0.0.1 - - [10/Oct/2023:13:57:01 +0800] "GET /api/products HTTP/1.1" 200 8901',
    '127.0.0.1 - - [10/Oct/2023:13:58:22 +0800] "GET /api/user HTTP/1.1" 200 1234',
    '192.168.1.2 - - [10/Oct/2023:13:59:45 +0800] "GET /api/products HTTP/1.1" 404 0'
]

# 分析日志
ip_counts = defaultdict(int)
endpoint_counts = defaultdict(int)
status_counts = defaultdict(int)

print("\n日志分析结果:")
for entry in log_entries:
    match = log_regex.match(entry)
    if match:
        ip = match.group(1)
        timestamp = match.group(2)
        method = match.group(3)
        path = match.group(4)
        protocol = match.group(5)
        status = match.group(6)
        size = match.group(7)
        
        ip_counts[ip] += 1
        endpoint_counts[path] += 1
        status_counts[status] += 1
        
        print(f"IP: {ip}, 时间: {timestamp}, 方法: {method}, 路径: {path}, 状态码: {status}")

print("\n统计信息:")
print("IP访问次数:", dict(ip_counts))
print("端点访问次数:", dict(endpoint_counts))
print("状态码统计:", dict(status_counts))

10.4、示例4:数据清洗和格式化

复制代码
import re

# 原始数据
raw_data = """
姓名: 张三, 电话: 138-1234-5678, 邮箱: zhangsan@example.com
姓名: 李四, 电话: (86)139-8765-4321, 邮箱: lisi123@gmail.com
姓名: 王五, 电话: 0086-189-12345678, 邮箱: wang.wu@company.org
姓名: 赵六, 电话: 12345678901, 邮箱: invalid.email
"""

# 提取信息的正则表达式
info_pattern = r"""
    姓名:\s*([^,]+),\s*       # 姓名
    电话:\s*([^,]+),\s*       # 电话
    邮箱:\s*([^\n]+)          # 邮箱
"""

# 电话号码标准化正则表达式
phone_pattern = r"""
    (?:\(?(\+?\d{2,3})\)?[-. ]?  # 国际区号
    (\d{3})[-. ]?                # 前3位
    (\d{4})[-. ]?                # 中间4位
    (\d{4})                      # 最后4位
"""

info_regex = re.compile(info_pattern, flags=re.VERBOSE)
phone_regex = re.compile(phone_pattern, flags=re.VERBOSE)

# 处理数据
print("数据清洗和格式化结果:")
for match in info_regex.finditer(raw_data):
    name = match.group(1).strip()
    raw_phone = match.group(2).strip()
    email = match.group(3).strip()
    
    # 标准化电话号码
    phone_match = phone_regex.search(raw_phone)
    if phone_match:
        country_code = phone_match.group(1) or '86'
        standardized_phone = f"+{country_code} {phone_match.group(2)} {phone_match.group(3)}-{phone_match.group(4)}"
    else:
        standardized_phone = "无效电话号码"
    
    # 验证邮箱
    if not re.match(r'^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$', email):
        email = f"无效邮箱: {email}"
    
    print(f"姓名: {name}")
    print(f"原始电话: {raw_phone}")
    print(f"标准电话: {standardized_phone}")
    print(f"邮箱: {email}")
    print("-" * 30)

10.5、示例5:高级文本处理(Markdown转换为HTML)

复制代码
import re

# Markdown文本
markdown_text = """
# 标题1

这是一个段落,包含**加粗**和*斜体*文本。

## 标题2

- 列表项1
- 列表项2
- 列表项3

[示例链接](https://example.com)
"""

# 转换规则
rules = [
    (r'^#\s+(.+)$', r'<h1>\1</h1>'),                    # 标题1
    (r'^##\s+(.+)$', r'<h2>\1</h2>'),                   # 标题2
    (r'\*\*(.+?)\*\*', r'<strong>\1</strong>'),         # 加粗
    (r'\*(.+?)\*', r'<em>\1</em>'),                     # 斜体
    (r'^-\s+(.+)$', r'<li>\1</li>'),                    # 列表项
    (r'\[(.+?)\]\((.+?)\)', r'<a href="\2">\1</a>'),    # 链接
    (r'^\s*$', r'<br>')                                 # 空行
]

# 编译所有正则表达式
compiled_rules = [(re.compile(pattern, flags=re.MULTILINE), replacement) 
                 for pattern, replacement in rules]

# 转换函数
def markdown_to_html(text):
    for pattern, replacement in compiled_rules:
        text = pattern.sub(replacement, text)
    
    # 处理列表
    text = re.sub(r'(<li>.+</li>)+', r'<ul>\g<0></ul>', text, flags=re.DOTALL)
    
    # 处理段落
    paragraphs = []
    for line in text.split('<br>'):
        line = line.strip()
        if line and not re.match(r'^<(h\d|ul|li)', line):
            line = f'<p>{line}</p>'
        paragraphs.append(line)
    
    return '\n'.join(filter(None, paragraphs))

# 执行转换
html_output = markdown_to_html(markdown_text)
print("Markdown转换为HTML结果:")
print(html_output)

10.6、示例6:密码强度验证

复制代码
import re

def validate_password(password):
    """
    验证密码强度:
    - 至少8个字符
    - 包含大写和小写字母
    - 包含数字
    - 包含特殊字符
    """
    if len(password) < 8:
        return False, "密码太短,至少需要8个字符"
    
    checks = [
        (r'[A-Z]', "需要至少一个大写字母"),
        (r'[a-z]', "需要至少一个小写字母"),
        (r'[0-9]', "需要至少一个数字"),
        (r'[^A-Za-z0-9]', "需要至少一个特殊字符")
    ]
    
    failed = []
    for pattern, message in checks:
        if not re.search(pattern, password):
            failed.append(message)
    
    if failed:
        return False, ",".join(failed)
    else:
        return True, "密码强度足够"

# 测试密码
passwords = [
    "weak",
    "Weak1",
    "Weak1!",
    "StrongPassword1!",
    "12345678",
    "ABCDEFGH",
    "Abc123!@#"
]

print("\n密码强度验证结果:")
for pwd in passwords:
    is_valid, message = validate_password(pwd)
    status = "✅" if is_valid else "❌"
    print(f"{status} {pwd}: {message}")
相关推荐
Cl_rown去掉l变成C12 分钟前
第R5周:天气预测
人工智能·python·深度学习·算法·tensorflow2
天下弈星~16 分钟前
变分自编码器VAE的Pytorch实现
图像处理·pytorch·python·深度学习·vae·图像生成·变分自编码器
这里有鱼汤32 分钟前
新型震荡器CyberOsc指标详解及完整策略源码(含图)
python
一百天成为python专家35 分钟前
OpenCV图像平滑处理方法详解
开发语言·人工智能·python·opencv·机器学习·支持向量机·计算机视觉
软测进阶43 分钟前
【Python】Python 函数基本介绍(详细版)
开发语言·python
Q_Q5110082851 小时前
python的滑雪场雪具租赁服务数据可视化分析系统
spring boot·python·信息可视化·django·flask·node.js·php
java1234_小锋1 小时前
一周学会Matplotlib3 Python 数据可视化-绘制散点图(Scatter)
开发语言·python·信息可视化·matplotlib·matplotlib3
爱刘温柔的小猪2 小时前
openai-agent使用本地模型并进行流式输出
python·ai
阿群今天学习了吗2 小时前
label studio 服务器端打开+xshell端口转发设置
linux·运维·服务器·笔记·python