别再用字符串切割了,摸金手套才是暗号解析的神器

4 阅读3分钟

很多人一听"正则表达式"五个字,脑瓜子嗡嗡的。什么点号、反斜杠、中括号、小括号,感觉跟进了黑灯瞎火的仓库,伸手不见五指,不知道从哪摸起。

其实特简单。正则就是你在黑暗仓库里的"摸金手势"。 手势做对了,闭着眼睛也能把想要的东西掏出来。


一、场景:仓库停电了

你刚用 requests 要饭成功,老板(服务器)给你扔过来一张菜单(HTML字符串)。但仓库停电了,你看不见,只能伸手摸。

菜单长这样:

<li class="food">蛋炒粉 - <span class="price">15元</span></li>
<li class="food">肉炒粉 - <span class="price">20元</span></li>

你的任务:在黑暗里,把所有价格(数字+元)摸出来。

老板给你一副摸金手套re模块),手套上刻着各种手势。你做什么手势,它就摸什么东西。


二、基础手势:单字符匹配

.(点号):摸到啥算啥,除了墙角的换行符

import re

html = "蛋炒粉15元\n肉炒粉20元"

# 点号:任意摸一个字符
re.findall(r'.', html)

人话. 就像你伸手随便抓一把,抓到字母、数字、符号都算数。但注意——抓不到墙角的换行符(\n)。

:在 Python 的 re 模块里,. 默认不匹配换行符。如果你的货(HTML)是好几行,点号摸到\n就停了。

解决办法:加上 re.DOTALL 标志,让点号变成"连墙角都能摸"。

re.findall(r'.+', html, re.DOTALL)  # 现在能跨行摸了

\d:只摸数字(digit)

html = "蛋炒粉15元"

re.findall(r'\d', html)  # ['1', '5']
re.findall(r'\d+', html) # ['15']  (+号表示"连续摸多个")

人话\d 就像你戴了数字感应手套,只摸 0-9,字母和汉字自动跳过。


\w:摸字母、数字、下划线(word)

html = "price_20"

re.findall(r'\w+', html)  # ['price_20']

人话\w 摸的是"单词字符"——字母、数字、下划线。中文它也能摸(看编码),但通常用来摸英文变量名、账号名。


\s:摸空白(space)

html = "蛋炒粉  15元"

re.findall(r'\s', html)  # [' ', ' ']  (两个空格)

人话\s 摸的是空白——空格、制表符(\t)、换行符(\n)都算。


\n\t:精确摸

手势摸什么
\n只摸换行符(回车)
\t只摸制表符(Tab键)

什么时候用? 你要把一段文本按行拆开,或者把表格数据按列拆开的时候。


三、定位手势:从哪开始摸,到哪结束

仓库很大,你不能乱摸,得知道从哪下手,到哪停手

^:从门口开始摸(字符串开头)

text = "15元一份"

re.findall(r'^15', text)  # ['15']  (开头是15,摸到了)
re.findall(r'^20', text)  # []      (开头不是20,没摸到)

人话^ 就像你站在仓库门口,只摸最开头的东西。开头不对,直接走人。


$:摸到墙根(字符串结尾)

text = "一份15元"

re.findall(r'15元$', text)  # ['15元']  (结尾是15元,摸到了)

人话$ 就像你摸到仓库最里面的墙根,只检查最后是什么

组合技^$ 一起用,可以判断"这行是不是空的"。

re.findall(r'^\s*$', text)  # 只摸空白行(全是空格或啥都没有)

四、反义手势:大写就是"不"

手套翻个面,大写就是反着摸

小写(摸这个)大写(不摸这个)
\d(数字)\D(非数字)
\w(单词字符)\W(非单词字符)
\s(空白)\S(非空白)
html = "价格15元"

# \D 摸到"价格"和"元"(非数字)
re.findall(r'\D+', html)  # ['价格', '元']

# \S 摸到所有非空白的东西
re.findall(r'\S+', html)  # ['价格15元']

人话:大写就是**"除了这个都摸"**。你记不住的时候,想想"大写=大佬,大佬不挑食"。


五、组合技:量词(摸几个?)

基础手势只能摸一个字符,但仓库里的货长度不一,你得告诉手套:摸几个?

量词人话示例
*0次或多次(可有可无)\d* → 数字可能有,可能没有
+1次或多次(至少有一个)\d+ → 至少一个数字(最常用)
?0次或1次(最多一个)https? → http 或 https
{n}恰好n次\d{3} → 恰好3个数字
{n,m}n到m次\d{2,4} → 2到4个数字

实战:摸手机号(11位数字)

phone = "我的电话是13812345678,备用13987654321"

re.findall(r'1\d{10}', phone)  
# 1开头,后面再摸10个数字,正好11位
# ['13812345678', '13987654321']

六、分组与选择:把货装篮子,或者二选一

|(竖线):或者

html = "老王炒粉店和老李烧烤摊"

re.findall(r'老王|老李', html)  # ['老王', '老李']

人话| 就是**"或者"**。摸老王也行,摸老李也行。


()(括号):分组装篮子

html = '<span class="price">15元</span>'

# 把数字单独装篮子里
re.findall(r'<span class="price">(\d+)元</span>', html)
# ['15']  (只返回括号里的东西)

人话:括号就像篮子。你摸了一整串,但只把篮子里的东西拿出来。

多个篮子

html = "2026-04-29"

re.findall(r'(\d{4})-(\d{2})-(\d{2})', html)
# [('2026', '04', '29')]  (年、月、日分别装三个篮子)

七、自定义范围:我只摸这几种

[...]:字符集(白名单)

html = "abc123ABC"

# 只摸小写字母
re.findall(r'[a-z]+', html)  # ['abc']

# 只摸数字和大写字母
re.findall(r'[0-9A-Z]+', html)  # ['123ABC']

人话:中括号里写**"允许摸的名单"**。[a-z] 就是小写字母全家桶,[0-9] 就是数字全家桶。


[^...]:排除集(黑名单)

html = "abc123"

# 除了小写字母,其他都摸
re.findall(r'[^a-z]+', html)  # ['123']

人话:中括号里加个 ^,就是**"禁止摸的名单"**。[^a-z] 就是"小写字母不准摸,其他的随便"。


八、Python里的坑(再提醒一遍)

说明解决办法
. 不匹配换行符多行HTML,点号摸到\n就断re.DOTALL
贪婪匹配.* 会尽可能多摸,连不该摸的都摸了? 变非贪婪:.*?
反斜杠灾难\d 在字符串里要先被Python解析一次字符串前加 r,写成 r'\d+'

贪婪 vs 非贪婪

html = "<span>15元</span><span>20元</span>"

# 贪婪(.*):尽可能多摸,把中间全吞了
re.findall(r'<span>(.*)</span>', html)  # ['15元</span><span>20元']

# 非贪婪(.*?):摸到第一个就停
re.findall(r'<span>(.*?)</span>', html)  # ['15元', '20元']

人话:贪婪就是"看到货全搂怀里",非贪婪就是"够一个就收手"。爬HTML的时候,99%的情况要用非贪婪 .*?


九、终极口诀(背下来)

点号摸万物,换行摸不到(要加DOTALL)。

\d是数字,\w是单词,\s是空白,大写全反义。

^在门口,$在墙根,定位不迷路。

*可有可无,+至少一个,?最多一个,{n,m}控制次数。

|是或者,()是篮子,中括号是白名单,[^]是黑名单。

贪婪搂到底,非贪婪加问号,爬网页用.*?


写在最后

下次再有人问你"正则怎么写",你就说:

"进黑仓库,戴摸金手套,做手势,掏东西。"

他要是问你"什么手势",你就把这篇口诀甩他脸上。

散会。