小白python入门 - 23. Python 正则表达式的应用

正则表达式的应用

1. 正则表达式概述

处理文本时,常需要按某种"规则"检查、提取或改写片段,例如从日志里找出订单号、校验表单字段格式、把敏感数字中间位打码。正则表达式(Regular Expression)就是描述这类规则的专用记法:它定义一种模式,用来判断字符串是否匹配,或从字符串中取出/替换匹配部分。

可以把它理解成比文件名通配符(*?)更精细的匹配语言:表达力更强,书写成本也更高。今天绝大多数语言都内置了正则支持;在 Python 中,标准库模块 re 负责编译与匹配。

更多语法可参考通用入门材料,例如 正则表达式 30 分钟入门。读完后,下表中的常用符号会更容易对照使用。

符号 含义 示例 说明
. 任意单个字符 c.t 可匹配 catc9t
\w 字母、数字、下划线 \w+ 一段"词"字符
\s 空白(空格、制表、换行等) id\s*= id= 之间允许空白
\d 数字 \d{4} 恰好 4 位数字
\b 单词边界 \bEND\b 独立单词 END
^ / $ 串首 / 串尾 ^ERR\.log$ 以 ERR 开头、以 .log 结尾
\W \S \D \B 与上面几类相反 \D+ 连续非数字
[...] / [^...] 字符集 / 取反 [A-Z][^0-9] 大写字母;非数字
* / + / ? 0 次及以上 / 1 次及以上 / 0 或 1 次 \d+ 至少一位数字
{n} {m,} {m,n} 固定或区间次数 \d{2,4} 2~4 位数字
` ` 分支(或) `GET
(exp) 捕获分组 (\d+)-(\d+) 可取各组内容
(?:exp) 非捕获分组 (?:ab)+ 只分组不捕获
(?=exp) / (?<=exp) 正向 / 反向先行断言 \d+(?=元) 数字后紧跟"元"
(?!exp) / (?<!exp) 负向断言 (?<!\d)\d{6}(?!\d) 恰好 6 位且两侧非数字
*? +? ?? {m,n}? 懒惰量词 a.*?b 尽可能短地匹配

说明: 若要匹配正则元字符本身,需转义,例如字面小数点写作 \.,字面括号写作 \( \)


2. Python 中的 re 模块

函数 / 标记 作用
compile(pattern, flags=0) 编译模式,得到可复用的正则对象
match(pattern, string, flags=0) 字符串开头 尝试匹配,成功返回匹配对象,否则 None
fullmatch(pattern, string, flags=0) 要求整串完全符合模式
search(pattern, string, flags=0) 在串中查找第一次出现
findall(pattern, string, flags=0) 返回所有匹配的字符串列表(有分组时结构会变化)
finditer(pattern, string, flags=0) 返回匹配对象的迭代器
split(pattern, string, maxsplit=0, flags=0) 按模式切分,返回列表
sub(pattern, repl, string, count=0, flags=0) 用替换内容替换匹配;repl 可为字符串或函数
purge() 清理隐式编译缓存
re.I / re.IGNORECASE 忽略大小写
re.M / re.MULTILINE 多行模式下 ^ $ 作用于每行

关键概念:

  • 同一模式若会多次使用,应先 compile,再调用对象的 match / search / findall 等方法。
  • 书写模式时推荐原始字符串 r'...',避免 \ 被 Python 字符串先转义一层(否则 \d 常要写成 \\d)。

多个 flags 可用按位或组合,例如 flags=re.I | re.M


3. 应用示例

3.1 校验工号与邮箱(match / fullmatch

规则约定:

  • 工号:2 位大写字母 + 4~6 位数字,整串合法(如 HR1024IT90001)。
  • 邮箱:本地部分允许字母数字、点、下划线、百分号、加号、减号;@ 后为域名片段。
python 复制代码
import re

staff_id = input('工号: ').strip()
email = input('邮箱: ').strip()

# match:从开头匹配;配合 ^...$ 等价于"整串符合"
m_id = re.match(r'^[A-Z]{2}\d{4,6}$', staff_id)
if not m_id:
    print('工号格式无效')

# fullmatch:整串必须完全匹配,模式里可不写 ^ $
m_mail = re.fullmatch(
    r'[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}',
    email,
)
if not m_mail:
    print('邮箱格式无效')

if m_id and m_mail:
    print('校验通过')

提示: match 只锚定开头;若未写 $AB1234xyz 在宽松模式下可能被误判为"从开头已匹配成功"。校验整字段时优先 fullmatch,或显式使用 ^...$


3.2 从日志中提取订单号(compile / findall / finditer / search

订单号形如 ORD- + 8 位数字。用前后断言避免与更长数字串粘连,并演示三种取结果的方式。

python 复制代码
import re

# 左侧非数字、右侧非数字,降低误匹配
pattern = re.compile(r'(?<!\d)ORD-\d{8}(?!\d)')

log_text = """
[INFO] create ORD-20250101 ok
retry ORD-20250102; noise ORD-20250102111 ignored
client sent ORD-20250315 and ORD-20250316
"""

# 方法一:全部匹配成列表
print(re.findall(pattern, log_text))

# 方法二:迭代匹配对象
for m in pattern.finditer(log_text):
    print(m.group(), 'at', m.start())

# 方法三:search 从上次结束位置继续扫
m = pattern.search(log_text)
while m:
    print(m.group())
    m = pattern.search(log_text, m.end())

关键点:

  • findall 适合只要文本;需要位置或分组细节时用 finditer
  • search(..., pos) 可从指定下标继续搜,适合手写扫描循环。

若号段规则更复杂,可把主体改成分支,例如 ORD-(?:20\d{6}|9\d{7}),再保留两侧断言。


3.3 脱敏证件号与手机号(sub

将 11 位手机号中间 4 位、18 位证件号中间若干位替换为 *repl 使用函数,按分组拼接。

python 复制代码
import re

def mask_sensitive(text: str) -> str:
    def repl_phone(m: re.Match) -> str:
        s = m.group()
        return s[:3] + '****' + s[7:]

    def repl_id(m: re.Match) -> str:
        s = m.group()
        return s[:4] + '*' * 10 + s[-4:]

    text = re.sub(r'(?<!\d)1\d{10}(?!\d)', repl_phone, text)
    text = re.sub(
        r'(?<!\d)\d{17}[\dXx](?!\d)',
        repl_id,
        text,
        flags=re.IGNORECASE,
    )
    return text


sample = '联系人 13812345678,证件 110101199001011234,备用 13900001111'
print(mask_sensitive(sample))
# 输出类似:联系人 138****5678,证件 1101**********1234,备用 139****1111

说明: flags=re.I(或 re.IGNORECASE)让证件末位 x/X 都能匹配。多个标志用 | 叠加。真实业务号段、校验位规则更严,此处仅演示替换接口。


3.4 按多种分隔符拆分配置行(split

配置项可能用逗号、分号或竖线分隔,分隔符后允许空格。

python 复制代码
import re

line = 'host=10.0.0.8; port=8080 | timeout=3, retries=2'
parts = re.split(r'[,;|]\s*', line)
fields = [p for p in parts if p]
for item in fields:
    print(item)
# host=10.0.0.8
# port=8080
# timeout=3
# retries=2

split 得到的列表可能含空串(首尾或连续分隔符),用列表推导过滤即可。需要限制段数时传入 maxsplit


总结

场景 常用接口
整字段是否合法 fullmatch,或 match + ^...$
取出全部片段 findall / finditer
从某位置继续找 search + 结束下标
改写匹配内容 sub(字符串或回调)
按模式切开 split
模式复用 compile

正则擅长结构化文本的校验、抽取与改写;模式越复杂,越建议用在线调试工具边写边测。业务规则变更时,优先收紧字符类与断言,并补上边界用例(空串、粘连数字、大小写),避免"能跑但误伤"。

`)

相关推荐
雪碧透心凉_2 小时前
while 循环与循环嵌套
开发语言·python
初学者,亦行者2 小时前
利用pyecharts自动化绘制漏斗图保姆级教程
python·信息可视化·数据分析
这就是佬们吗2 小时前
Python入门⑤-异常处理、文件操作与实战项目
开发语言·数据库·python·算法·pycharm
卷无止境2 小时前
提升 Python 代码健壮性的方法大盘点
后端·python
asdzx672 小时前
Python PDF 拆分实战指南:单页拆分与按需页码范围拆分
开发语言·python·pdf
LadenKiller3 小时前
近期AI训练量化表达,解释改写检查要按顺序
人工智能·python
李昊哲小课3 小时前
咖啡工坊 · FastAPI 22 章教程合集
服务器·人工智能·python·fastapi
卷无止境3 小时前
Python 异常处理:从入门到工程实践
后端·python
garuda herb3 小时前
生成专题页Blog--建立并返回 MySQL 数据库连接
python·mysql