
一行日志拆错,后面的字段全歪了。
原始数据长这样:
2026-06-04 10:21:33 | order_id=77881, user_id=1024; status=PAID amount=199
有人直接写:
line.split(" ")
我看到这种写法一般会皱一下眉。空格数量一变,字段位置就乱;分隔符从逗号换成分号,又要补一坨判断。Python 里处理这种脏字符串,re 模块里的 split()、sub()、subn() 反而更像干活用的刀。
先看 re.split()。
它不是按固定字符切,而是按正则规则切。日志、导入文件、运营后台导出的 CSV,最常见的问题就是分隔符不老实:有时一个空格,有时多个空格,有时逗号、分号、竖线混着来。
import re
line = "order_id=77881, user_id=1024; status=PAID amount=199"
parts = re.split(r"[,;\s]+", line)
print(parts)
# ['order_id=77881', 'user_id=1024', 'status=PAID', 'amount=199']
这里的 [,;\s]+ 我平时会这么写,意思是:逗号、分号、空白字符,都算分隔符,而且连续出现也只切一次。
这比一层层 replace() 再 split() 干净多了。
有个细节要注意,如果正则里用了捕获括号,分隔符也会被保留下来。这个坑我见过几次,排查半天发现是括号多写了。
text = "A, B; C"
print(re.split(r"[,;]\s*", text))
# ['A', 'B', 'C']
print(re.split(r"([,;])\s*", text))
# ['A', ',', 'B', ';', 'C']
如果你不是故意要保留分隔符,就别随手加括号。真要分组但不想保留,用 (?:...)。
print(re.split(r"(?:[,;])\s*", text))
# ['A', 'B', 'C']
再看 re.sub()。
这个更常用,替换。不是简单字符串替换,而是按模式替换。
比如接口日志里手机号要脱敏,别写一堆切片,字段格式一变就崩。直接按手机号规则处理。
import re
log = "buyer=13812345678 receiver=13988887777 order=77881"
safe_log = re.sub(
r"(?<!\d)(1[3-9]\d)\d{4}(\d{4})(?!\d)",
r"\1****\2",
log
)
print(safe_log)
# buyer=138****5678 receiver=139****7777 order=77881
这段正则看着长一点,但它做了两件事:只处理 11 位手机号;前后不能再跟数字,避免把一串订单号中间误伤。
re.sub() 的第三个参数是替换后的内容。这个内容可以是字符串,也可以是函数。函数替换在清洗数据时特别顺手。
比如运营导入金额,有人填 ¥1,299.00,有人填 299 元,还有人复制了全角空格。入库前先清一下:
import re
from decimal import Decimal
raw_amounts = ["¥1,299.00", " 299 元", "39.9"]
def normalize_amount(value: str) -> Decimal:
value = value.translate(str.maketrans("0123456789.", "0123456789."))
value = re.sub(r"[^\d.]", "", value)
if not value:
raise ValueError("金额为空,不能入库")
return Decimal(value)
for item in raw_amounts:
print(normalize_amount(item))
这里我没有上来就写复杂正则。先把全角数字转半角,再把非数字和小数点干掉。代码是给以后排问题的人看的,不是给正则比赛看的。
sub() 还有一个 count 参数,能限制替换次数。
这个在处理日志头的时候挺有用,比如只去掉第一段时间,不动后面的业务内容。
import re
line = "2026-06-04 10:21:33 ERROR create_time=2026-06-01 msg=failed"
clean = re.sub(
r"^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\s+",
"",
line,
count=1
)
print(clean)
# ERROR create_time=2026-06-01 msg=failed
如果不加开头的 ^,或者不限制范围,后面的业务时间也可能被你顺手干掉。线上清洗脚本最怕这种“看起来没报错”的错。
最后是 re.subn()。
它和 sub() 很像,也是替换,但会多返回一个数字:替换了几次。
这个数字很有用。批量脚本里,我一般不会只关心结果,还要知道到底动了多少数据。尤其是清洗手机号、身份证、异常字符这种操作,替换次数就是一个很便宜的校验指标。
import re
rows = [
"user=tom phone=13812345678",
"user=jerry phone=",
"user=lucy phone=13988887777"
]
for row in rows:
masked, hit = re.subn(
r"(?<!\d)(1[3-9]\d)\d{4}(\d{4})(?!\d)",
r"\1****\2",
row
)
if hit == 0:
print(f"[WARN] 未找到手机号: {row}")
continue
print(masked)
输出大概是这样:
user=tom phone=138****5678
[WARN] 未找到手机号: user=jerry phone=
user=lucy phone=139****7777
subn() 适合放在批处理、导入校验、日志脱敏这类场景里。它不是功能更强,而是更适合排查。脚本跑完,你至少知道命中了多少条,没命中的数据要不要丢出来看一眼。
这三个方法放一起看,区别挺清楚。
split() 管拆。字符串里分隔符不固定,用它。
sub() 管替换。脱敏、清洗、格式修正,用它。
subn() 也是替换,但顺手告诉你替换了几次。批量处理时,我更喜欢它,心里有数。
最后补一句,正则别写得太玄。
能用一条简单规则解决,就别堆十几个分支。真遇到复杂数据,宁可拆成两三步处理,中间打印一下样本,也别把所有逻辑塞进一条正则里。后面出问题的时候,你会感谢当时那个没逞强的自己。
以上就是“Python 的 re 模块中 split()、sub()、subn() 方法有什么作用?”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14228/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料