1. 初识re.findall()从字符串中抓取目标内容第一次接触正则表达式时我被那些奇怪的符号组合搞得一头雾水。直到发现re.findall()这个神器才真正体会到正则表达式的强大。简单来说re.findall()就像个智能搜索工具能帮你从大段文字中快速找出所有符合特定规则的片段。举个例子假设你手头有份客户反馈文档里面混着电话号码。用肉眼找号码简直是大海捞针但用re.findall()只需三行代码import re text 客户张三电话13800138000李四电话15912345678投诉内容... phones re.findall(r1[3-9]\d{9}, text) print(phones) # 输出[13800138000, 15912345678]这里的r1[3-9]\d{9}就是正则表达式模式意思是1以数字1开头[3-9]第二位是3-9中的任意数字\d{9}后面跟着9位数字最近帮朋友处理Excel数据时发现有个字段混着产品编号和描述文字。产品编号都是AB开头加6位数字用re.findall()轻松搞定mixed_data AB123456 红色款, AB654321 蓝色款, 无编号商品 product_ids re.findall(rAB\d{6}, mixed_data)这种基础匹配看似简单但在实际工作中能解决80%的文本提取需求。特别是在处理日志文件时经常需要提取特定格式的时间戳或错误代码re.findall()都能派上大用场。2. 进阶匹配技巧分组捕获与非贪婪模式当我们需要提取结构化数据时单纯匹配整个字符串就不够用了。这时就要用到分组捕获——用圆括号标记需要单独提取的部分。去年做爬虫项目时我需要在HTML中同时抓取商品名称和价格分组功能帮了大忙。看这个电商页面片段div classitemiPhone14 ¥6999/div div classitemMate50 ¥5999/div用分组捕获可以一次性提取商品名和价格html div classitemiPhone14 ¥6999/div div classitemMate50 ¥5999/div pattern r(\w)\s¥(\d) results re.findall(pattern, html) # 结果[(iPhone14, 6999), (Mate50, 5999)]这里(\w)捕获商品名(\d)捕获价格返回的是元组列表。有个坑我踩过如果想用.*匹配任意字符一定要加上?启用非贪婪模式。有次抓取新闻时原始写法title(.*)/title把整个页面内容都吞掉了改成title(.*?)/title才正确。实际工作中处理JSON字符串时这种技巧特别有用json_str {name:张三,age:25},{name:李四,age:30} data re.findall(rname:(.*?).*?age:(\d), json_str)3. 字符集与取反操作实战字符集[]就像点菜时的多选菜单可以匹配方括号内的任意字符。上周处理客户地址数据时需要提取所有包含区或县的行政区划addresses 朝阳区 海淀区 昌平区 密云县 通州区 areas re.findall(r[区县], addresses) # [区, 区, 区, 县, 区]更实用的是取反操作[^]相当于除了这些都要。处理产品编码时需要过滤掉所有非字母数字字符product_code A1B2-C3D4E5F6 clean_code re.findall(r[^\-], product_code) # 结果[A,1,B,2,C,3,D,4,E,5,F,6]结合量词可以优化结果clean_code .join(re.findall(r[^\-], product_code)) # 输出A1B2C3D4E5F6最近有个有趣的案例需要从混合文本中提取所有非中文内容。用Unicode范围实现起来很优雅text Hello世界123こんにちは non_chinese re.findall(r[^\u4e00-\u9fa5], text) # 结果[Hello, 123, こんにちは]4. 综合实战网页数据抓取与清洗真实项目中最常遇到的是混合了各种特殊字符的脏数据。去年爬取某电商网站时商品价格可能带着¥、$符号或者促销价等前缀。最终我用了多层过滤price_text 现价¥1299 原价$1599 促销价899 prices re.findall(r(?:¥|\$|价)(\d), price_text) # 结果[1299, 1599, 899]这里(?:)表示非捕获分组只用于匹配但不提取。更复杂的案例是处理嵌套HTML比如提取所有超链接及其文本html a hrefhttps://example.com首页/aa href/about关于/a links re.findall(ra\shref[\](.*?)[\].*?(.*?)/a, html) # 结果[(https://example.com, 首页), (/about, 关于)]处理中文文本时经常需要识别特定短语。比如从新闻中提取所有XX表示的句式content 外交部发言人表示... 专家分析指出... 企业代表表示... statements re.findall(r([\u4e00-\u9fa5]?)表示, content) # 结果[外交部发言人, 企业代表]5. 性能优化与常见陷阱随着数据量增大正则表达式性能问题就会显现。有次处理10GB日志文件时原始脚本跑了2小时。通过预编译正则表达式和优化模式最终缩短到15分钟# 错误示范每次循环都重新编译 for line in log_file: ips re.findall(r\d\.\d\.\d\.\d, line) # 正确做法预编译 ip_pattern re.compile(r\d\.\d\.\d\.\d) for line in log_file: ips ip_pattern.findall(line)另一个常见错误是过度使用.匹配任意字符。在分析XML文件时我最初用tag(.*)/tag匹配内容结果在嵌套标签时出错。应该用([^]*)限制不包含尖括号xml noteto张三/tofrom李四/from/note re.findall(rto([^]*)/to, xml) # 正确匹配张三处理多行文本时记得使用re.DOTALL标志。有次提取跨行代码注释很头疼code /* 第一行注释\n第二行注释 */ comment re.findall(r/\*(.*?)\*/, code, re.DOTALL)最后分享个实用技巧当需要从复杂文本中提取多种模式时可以组合多个re.findall()。比如同时提取邮件和电话text 联系adminexample.com 电话13800138000 emails re.findall(r\b[\w.-][\w.-]\.\w\b, text) phones re.findall(r1[3-9]\d{9}, text)