Python编程快速上手——正则表达式查找功能案例分析

发布时间:2026/10/12 10:36:20

Python编程快速上手——正则表达式查找功能案例分析 前言「查找」是正则最基础也最实用的功能从一段没有结构的文字里把符合某种形状的信息一条条揪出来。这听起来简单但真做起来选择findall还是finditer、要不要用命名分组、怎么处理缺失字段都会影响结果质量。本文用一个完整的案例把「查找」讲透手头有一段参会人员名单每行的格式不完全整齐字段之间空格数量不一个别行还缺字段。目标是把它解析成结构化的记录列表。这类「半结构化文本」正是正则查找的主场。顺便纠正一个常见误解不要指望一个邮箱正则能匹配「所有合法邮箱」。RFC 对邮箱地址的规定极其宽松实践中通用的做法是「只匹配你确实会遇到的那一类宁可漏也不要错」需要严格校验时交给专门的校验环节而不是无限膨胀正则。示例基于 Python 3.8。一、案例数据与目标待处理的文本大致长这样字段用空白分隔但空白多少不定有缺失值张伟 13800138000 zhangweiexample.com李娜 13912345678 linatest.org王强 137-0000-1111 wangdemo.cn赵敏 无 zhaominexample.com目标是逐行提取出姓名、电话、邮箱。难点有三处空白数量不固定电话有带连字符和不带两种写法有的行电话号码位置写的是「无」。二、先定模式再选函数re的查找类函数有四个本案例该选哪个取决于「要结果还是要过程」函数返回是否带分组信息适用re.search第一个Match或None有只关心有没有、第一条re.match从开头匹配的Match有每行字段固定在行首re.findall字符串 / 元组列表分组退化成元组只要字段值re.finditerMatch迭代器完整保留要用命名分组、位置信息本案例要按名字取值findall一旦出现多个分组就只能拿到元组丢了名字信息所以选re.finditer。三、完整实现# 适用于 Python 3.8import retext 张伟 13800138000 zhangweiexample.com李娜 13912345678 linatest.org王强 137-0000-1111 wangdemo.cn赵敏 无 zhaominexample.comRECORD re.compile(r(?Pname[一-鿿]{2,4})\sr(?Pphone1[3-9]\d{9}|[\d-]{7,}|无)\sr(?Pemail[A-Za-z0-9._%-][A-Za-z0-9.-]\.[A-Za-z]{2,}))records []for m in RECORD.finditer(text):d m.groupdict() # {name: ..., phone: ..., email: ...}phone_digits re.sub(r\D, , d[phone]) # 去掉连字符等非数字records.append({name: d[name],phone: phone_digits or d[phone], # 「无」清理后为空保留原值email: d[email],})for r in records:print(r)各部分拆开看(?Pname[一-鿿]{2,4})中文姓名按 2 到 4 个汉字估算。一到鿿覆盖 CJK 统一表意文字基本区是常见的中文匹配区间。\s字段之间的分隔空白一个或多个都行正好解决空格数量不等的问题。(?Pphone1[3-9]\d{9}|[\d-]{7,}|无)三种可接受形态。第一支是标准 11 位手机号第二支容忍带连字符的写法第三支直接接受「无」。re.sub(r\D, , ...)\D是「非数字」的补集把连字符之类清掉再存。m.groupdict()返回的就是「名字到内容」的字典再配合.items()遍历Python 3 里.items()返回视图Python 2 的dict.iteritems()早已被移除不要再用旧写法。四、加一层校验与容错真实数据里难免有整行不匹配的情况。finditer只产出匹配上的记录漏掉的行不会报错也不会提示所以最好顺手记一笔# 适用于 Python 3.8import relines [张伟 13800138000 zhangweiexample.com, 格式不对的一行]RECORD re.compile(r(?Pname[一-鿿]{2,4})\sr(?Pphone1[3-9]\d{9}|[\d-]{7,}|无)\sr(?Pemail[A-Za-z0-9._%-][A-Za-z0-9.-]\.[A-Za-z]{2,}))ok, bad [], []for line in lines:m RECORD.fullmatch(line) # 整行匹配避免只匹配到前一部分if m:ok.append(m.groupdict())else:bad.append(line)print(解析成功, len(ok))print(跳过, bad)这里用一个fullmatch的思路做校验只有整行都符合模式才算解析成功避免模式只匹配到前半截、后半截被静默丢弃。re.fullmatch需要 Python 3.4更早的版本可以给模式末尾加\Z再配合re.match。五、让查找更稳的两个技巧技巧一用边界断言防止「切到别人一半」。手机号模式1[3-9]\d{9}在一串更长的数字里也能命中中间一段例如长订单号里的连续数字。用前后断言把它卡住# 适用于 Python 3.8import res 订单号 9913800138000888 联系 13800138000loose re.findall(r1[3-9]\d{9}, s)strict re.findall(r(?!\d)1[3-9]\d{9}(?!\d), s)print(loose) # [13800138000, 13800138000]长号码里也切出了一段print(strict) # [13800138000]只保留前后都不是数字的(?!\d)和(?!\d)是前后向断言本身不消耗字符只检查紧邻位置是不是数字因此不会影响匹配到的文本本身。技巧二多行日志用re.MULTILINE按行查找。带^、$的按行模式配合re.findall统计很方便# 适用于 Python 3.8import refrom collections import Counterlog GET /a 200\nGET /b 404\nPOST /a 200\nGET /a 200codes re.findall(r\s(\d{3})$, log, flagsre.MULTILINE)print(Counter(codes)) # Counter({200: 3, 404: 1})默认情况下$只匹配整串末尾加了re.MULTILINE行内写(?m)后才会匹配每一行末尾。常见坑点❌ 用re.findall拿带命名分组的结果以为会返回字典实际得到的是元组列表。✅findall会丢命名信息需要按名字取值就用re.finditer配m.groupdict()。❌ 用re.match逐行解析字段不在行首的行全部漏掉。✅ 字段固定在行首才用match游离位置用search或finditer。❌ 邮箱模式写成\S\S把紧跟其后的标点也一起吞进地址里。✅ 用字符集限定如[A-Za-z0-9._%-][A-Za-z0-9.-]\.[A-Za-z]{2,}宁可窄一点。❌ 用re.fullmatch校验整行时不检查返回值缺失字段的行被当成解析成功。✅fullmatch失败返回None必须先判断if m:再取值。❌ 分隔符写死成一个空格r(\w) (\d)遇到两个空格的行就匹配不上。✅ 用\s表示「一个或多个空白」对排版差异更宽容。❌ 用贪心的.*拼模式跨字段把后面几列一起吞掉。✅ 用精确的字符集\S、[^,]或者懒惰的.*?把匹配范围卡住。❌ 提取出来的电话号码直接拿去比较带连字符和不带连字符的同一号码被当成两个。✅ 先re.sub(r\D, , s)归一化再比较同时保留原始值用于展示。❌ 在循环里对同一段文本反复调用re.compile把每次查找都变成一次重新编译。✅ 模式在循环外编译一次re内部虽有缓存但显式编译更清晰也更可控。总结环节选择理由逐条提取re.finditer保留命名分组与位置整行校验re.fullmatch避免半截匹配字段容错交替分支 归一化re.sub(r\D, , s)比较前统一格式漏行记录遍历 else分支不静默丢数据正则查找的功夫一半在写模式一半在选函数。模式要「窄」——用具体字符集而不是.*用\s容忍排版差异函数要「对」——需要字段名就用finditer需要整行校验就用fullmatch。把这两件事分开想清楚半结构化文本的提取就稳了。
延伸阅读

更多相关文章

2026/10/12 10:36:20

支付架构调用流程详解:掉单排查与对账机制实战

先说个真实经历。有一年大促前夜,我们团队负责的某电商项目支付链路刚做完一波优化,第二天流量一上来,客服系统瞬间被“支付成功但订单仍是待支付”的工单淹没。当时我不信邪,从网关日志一路查到回调服务,最后发现不是…

2026/10/12 10:36:20

LDA主题分析实战:豆瓣长评论建模全流程与Python实现

简介:这是一套基于LDA主题模型的豆瓣长评论分析项目,面向需要完成NLP方向毕业设计、课程设计的学生,也适合希望快速上手文本主题建模的开发者。项目覆盖数据预处理、停用词过滤、LDA建模、困惑度与主题一致性评估,以及词云、主题热…

2026/10/12 10:36:20

短视频电商的病毒式传播:从货找人到直播间收割

你有没有发现,身边越来越多的朋友买东西的方式变了?以前是“想买什么去搜一下”,现在是刷着刷着视频,突然被一个十几秒的片段勾住,顺手就下了单。我在这个行业里摸爬滚打几年,亲眼看着短视频内容电商&#…

2026/10/12 15:42:31

EmbeddingGemma 2多模态嵌入模型本地部署实践:打通文本与图像检索

最近我在整理一个内部知识库,产品文档和操作截图混在一起,搜索体验很割裂:文本只能搜文本,图片只能靠文件名猜内容。我想找一张“流程图里带消息队列模块”的截图,传统文本检索根本帮不上忙。于是我开始折腾 Embedding…

2026/10/12 15:42:31

Spring JDBC中query与queryForObject的本质区别与避坑指南

1. 为什么这个区别值得花一整晚去抠?——从一次线上告警说起那天凌晨两点,某跨平台系统监控突然飙红:数据库连接池持续满载,平均响应时间从80ms跳到2300ms。值班的A同学紧急回滚了刚上线的用户画像模块,但指标纹丝不动…

2026/10/12 15:42:31

底噪思维:从信号监测到异常识别的工程实践指南

1. 从“底噪”这个词说起:为什么第二章要叫这个名字 “现代战争前传”这个系列做到第二章,标题定为“底噪”,我第一反应是——这名字起得真准。底噪是什么?玩过音频设备的人都知道,那是信号之外一直存在的、低沉的、持…

2026/10/12 15:42:31

IPT_LMT语音网关排障实战:从注册失败到语音质量定位

简介:华为语音网关调试工具IPT_LMT是面向通信运维工程师的专用诊断维护工具,主要适配eSpace U1900和SoftCo V200R003C20SPC300两个版本,用于话路状态监控、媒体参数检查、日志溯源、故障模拟,并支持自定义脚本完成批量操作与自动化…

2026/10/12 15:42:31

Linux孤儿进程与僵尸进程详解:wait和waitpid回收机制实战

1. 进程生命周期里那两个绕不开的"异常状态"但凡在Linux上写过一点系统编程,或者排查过线上服务的资源异常,迟早会撞上两个听起来有点吓人的名词:孤儿进程和僵尸进程。我第一次接触这两个概念的时候,脑子里浮现的画面相…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/12 0:04:22

绝缘子缺陷检测数据集清洗与工业级训练实战指南

简介:本资源是面向电力AI研发人员、工业视觉工程师及智能巡检系统开发者的绝缘子缺陷检测专用YOLO格式数据集,解决无人机航拍场景下绝缘子破损、污闪、积雪等9类典型缺陷的精准识别与定位难题。数据集共2139张真实巡检图像(含训练/验证/测试集…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑