pin_drop当前位置:知识文库 ❯ 图文

Python正则表达式常用模式 - 邮箱手机号URL验证大全

一、邮箱地址匹配

邮箱地址是最常见的需要验证的数据格式之一。一个标准的邮箱地址由用户名、@符号和域名三部分组成。

代码示例

import re

# 基础邮箱匹配模式
email_pattern = r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+"

# 测试邮箱地址
emails = [
    "user@example.com",           # 有效
    "test.user@company.co.uk",    # 有效
    "admin@sub.domain.org",       # 有效
    "invalid-email",              # 无效
    "@missing.com",               # 无效
    "user@.com",                  # 无效
]

for email in emails:
    match = re.fullmatch(email_pattern, email)
    status = "有效" if match else "无效"
    print(f"{email}: {status}")

更严格的邮箱验证模式,符合RFC 5322标准:

代码示例

import re

# 严格邮箱匹配(支持更多合法字符)
strict_email = r"(?P<local>[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+)@(?P<domain>[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)"

def validate_email(email):
    match = re.fullmatch(strict_email, email)
    if match:
        return {
            "valid": True,
            "local": match.group("local"),
            "domain": match.group("domain")
        }
    return {"valid": False}

# 测试
result = validate_email("hello.world@gmail.com")
print(result)
# {'valid': True, 'local': 'hello.world', 'domain': 'gmail.com'}

二、手机号码验证

中国大陆手机号码以1开头,第二位通常为3-9,总共11位数字。以下是常用的手机号验证模式:

代码示例

import re

# 中国大陆手机号验证
phone_pattern = r"^1[3-9]\d{9}$"

phones = [
    "13800138000",    # 有效 - 移动
    "15912345678",    # 有效 - 联通
    "18612345678",    # 有效 - 电信
    "12345678901",    # 无效 - 第二位不是3-9
    "1380013800",     # 无效 - 位数不够
    "138001380001",   # 无效 - 位数过多
]

for phone in phones:
    match = re.match(phone_pattern, phone)
    print(f"{phone}: {'有效' if match else '无效'}")

代码示例

import re

# 更详细的运营商识别
def identify_carrier(phone):
    if not re.match(r"^1[3-9]\d{9}$", phone):
        return "无效的手机号码"
    
    prefix = phone[:3]
    carrier_map = {
        "134": "移动", "135": "移动", "136": "移动", "137": "移动", "138": "移动", "139": "移动",
        "150": "移动", "151": "移动", "152": "移动", "157": "移动", "158": "移动", "159": "移动",
        "130": "联通", "131": "联通", "132": "联通", "155": "联通", "156": "联通", "185": "联通", "186": "联通",
        "133": "电信", "153": "电信", "180": "电信", "181": "电信", "189": "电信",
    }
    return carrier_map.get(prefix, "未知运营商")

print(identify_carrier("13800138000"))  # 移动
print(identify_carrier("18612345678"))  # 联通
print(identify_carrier("18912345678"))  # 电信

三、URL链接匹配

URL匹配需要考虑协议、域名、端口、路径和查询参数等多个部分。

代码示例

import re

# 匹配完整URL
url_pattern = r"(?P<protocol>https?|ftp)://(?P<host>[^\s:/]+)(?::(?P<port>\d+))?(?P<path>/[^\s?]*)?(?:\?(?P<query>[^\s#]*))?"

urls = [
    "https://www.example.com",
    "http://api.test.com:8080/v1/users?page=1&size=10",
    "ftp://files.server.com/docs/report.pdf",
    "https://example.com/path/to/page#section1",
]

for url in urls:
    match = re.search(url_pattern, url)
    if match:
        d = match.groupdict()
        print(f"协议: {d['protocol']}, 主机: {d['host']}, 端口: {d['port'] or '默认'}")
        print(f"  路径: {d['path'] or '/'}, 参数: {d['query'] or '无'}")
        print()

代码示例

import re

# 从文本中提取所有URL
text = """
访问我们的网站 https://www.example.com 或
API文档 http://api.example.com/docs
FTP服务器 ftp://ftp.example.com/pub
"""

# 简单的URL提取模式
extract_pattern = r"https?://[^\s<>\"]+|ftp://[^\s<>\"]+"
urls_found = re.findall(extract_pattern, text)

for url in urls_found:
    print(url)

四、IP地址匹配

IPv4地址由4个0-255之间的数字组成,用点号分隔。精确匹配需要确保每个段的数值范围正确。

代码示例

import re

# 精确的IPv4地址匹配
ipv4_pattern = r"^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$"

ips = [
    "192.168.1.1",       # 有效
    "10.0.0.1",          # 有效
    "255.255.255.255",   # 有效
    "256.1.2.3",         # 无效 - 256超出范围
    "192.168.1",         # 无效 - 只有3段
    "192.168.01.1",      # 无效 - 有前导零
]

for ip in ips:
    match = re.match(ipv4_pattern, ip)
    print(f"{ip}: {'有效' if match else '无效'}")

代码示例

import re

# IPv6地址匹配(简化版)
ipv6_pattern = r"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$"

ipv6_addresses = [
    "2001:0db8:85a3:0000:0000:8a2e:0370:7334",  # 有效
    "::1",                                        # 有效(简化形式)
    "fe80::1",                                    # 有效(简化形式)
    "2001:db8::8a2e:370:7334",                    # 有效(简化形式)
]

# 完整的IPv6模式较为复杂,以上为简化匹配
# 实际项目中建议使用 ipaddress 模块进行验证
import ipaddress

def validate_ipv6(addr):
    try:
        ipaddress.IPv6Address(addr)
        return True
    except ValueError:
        return False

for addr in ipv6_addresses:
    print(f"{addr}: {'有效' if validate_ipv6(addr) else '无效'}")

五、身份证号验证

中国大陆身份证号有15位(旧版)和18位(新版)两种格式,18位身份证最后一位可能是数字或X。

代码示例

import re

# 身份证号基本格式验证
id_card_pattern = r"^\d{17}[\dXx]$|^\d{15}$"

id_cards = [
    "11010519491231002X",   # 有效 - 18位
    "110105194912310021",   # 有效 - 18位
    "110105491231002",      # 有效 - 15位
    "11010519491231002",    # 无效 - 17位
    "11010519491231002Y",   # 无效 - 最后一位不是X
]

for card in id_cards:
    match = re.match(id_card_pattern, card)
    print(f"{card}: {'有效' if match else '无效'}")

代码示例

import re

# 更详细的身份证信息提取
def parse_id_card(id_card):
    if not re.match(r"^\d{17}[\dXx]$", id_card):
        return None
    
    area = id_card[:6]
    birth_year = id_card[6:10]
    birth_month = id_card[10:12]
    birth_day = id_card[12:14]
    gender = "男" if int(id_card[16]) % 2 == 1 else "女"
    check_code = id_card[17].upper()
    
    return {
        "地区码": area,
        "出生日期": f"{birth_year}-{birth_month}-{birth_day}",
        "性别": gender,
        "校验码": check_code
    }

info = parse_id_card("110105199001011234")
for key, value in info.items():
    print(f"{key}: {value}")

六、其他常用模式汇总

模式类型 正则表达式 匹配示例
邮政编码 ^\d{6}$ 100000, 518000
用户名 ^[a-zA-Z0-9_]{4,16}$ user_123, admin
密码强度 ^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$ pass1234, abcDEF12
日期格式 ^\d{4}-\d{2}-\d{2}$ 2024-12-25
时间格式 ^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$ 14:30:00, 08:00:00
车牌号 ^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼][A-Z][A-HJ-NP-Z0-9]{5}$ 京A12345
十六进制颜色 ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ #FFF, #2196F3
MAC地址 ^([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$ 00:1A:2B:3C:4D:5E

代码示例

import re

# 常用模式字典,方便直接调用
PATTERNS = {
    "email": r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+",
    "phone": r"^1[3-9]\d{9}$",
    "ipv4": r"^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$",
    "postal_code": r"^\d{6}$",
    "username": r"^[a-zA-Z0-9_]{4,16}$",
    "date": r"^\d{4}-\d{2}-\d{2}$",
    "time": r"^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$",
    "hex_color": r"^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$",
}

def validate(pattern_name, value):
    """通用验证函数"""
    pattern = PATTERNS.get(pattern_name)
    if not pattern:
        return False
    return bool(re.fullmatch(pattern, value))

# 使用示例
print(validate("email", "test@example.com"))     # True
print(validate("phone", "13800138000"))          # True
print(validate("ipv4", "192.168.1.1"))           # True
print(validate("postal_code", "100000"))         # True
print(validate("hex_color", "#2196F3"))          # True

小贴士

正则表达式虽然强大,但对于复杂的数据验证(如身份证号校验码、邮箱RFC标准等),建议结合专用库使用。Python内置的 ipaddress 模块可以替代正则验证IP地址,email_validator 库可以更准确地验证邮箱。

注意:以上模式仅做格式校验,不验证数据的真实性。例如手机号正则只能验证格式是否正确,不能确认该号码是否存在。实际业务中需要结合短信验证码、API接口等方式进行二次验证。

常见问题

邮箱正则表达式为什么看起来这么复杂?

因为RFC 5322标准对邮箱地址的定义非常灵活,用户名部分可以包含字母、数字以及多种特殊字符(.!#$%&'*+/=?^_`{|}~-)。简单模式可能漏掉合法邮箱或接受非法格式,需要根据实际需求在简洁和严格之间取舍。

如何验证身份证号的合法性(不仅是格式)?

18位身份证最后一位是校验码,可以通过前17位按照ISO 7064:1983.MOD 11-2算法计算得出。完整的验证需要:1)校验格式 2)校验出生日期合法性 3)校验校验码是否正确。建议使用第三方库如 id-validator

为什么IP地址验证不使用简单的 \d+\.\d+\.\d+\.\d+?

因为 \d+ 会匹配任意长度的数字,像 999.999.999.999 也会被匹配,但这不是合法的IP地址。每个段必须在0-255范围内,所以需要使用 (25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d) 来精确匹配。

密码验证正则是如何工作的?

(?=.*[A-Za-z]) 是正向先行断言,确保至少包含一个字母;(?=.*\d) 确保至少包含一个数字;[A-Za-z\d]{8,} 规定只能包含字母和数字且长度至少8位。这些条件通过先行断言组合在一起。

练习1

编写一个函数,接收一段文本,提取其中所有的邮箱地址和手机号,并返回分类后的结果字典。

练习2

创建一个表单验证类,使用正则表达式验证用户输入的用户名、密码、邮箱和手机号,返回详细的错误信息。

标签: 正则表达式 邮箱验证 手机号验证 IP地址 URL匹配 身份证验证 表单验证

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python正则贪婪与非贪婪匹配 - 量词使用与回溯优化技巧 下一篇: Python SQLite数据库操作教程 - sqlite3模块使用指南

poll相关推荐