str.extract只提取每行第一个匹配的数字,因其设计为“首匹配提取”,类似re.search();多数字需用str.findall()或str.extractall()。

str.extract 为什么只能提取第一个匹配的数字
str.extract 默认使用捕获组 (...) 定义要提取的内容,且只返回每行**第一个成功匹配的结果**。如果你的字符串里有多个数字(比如 "订单号:123,金额:456.78"),str.extract(r'(\d+)') 只会拿到 "123",后面的 "456" 被忽略。
这是设计使然,不是 bug。它对标的是“从每行中抽一个结构化字段”,类似从日志里提 request_id —— 通常只要一个。
- 想提全部数字?改用
str.findall(r'\d+'),返回 list,再用explode()展开 - 想提带小数点的数字?正则得写成
r'(\d+\.\d+|\d+)',注意顺序:浮点优先,否则\d+先匹配掉整数部分 - 空值处理:没匹配上的行会变成
NaN,如果后续要转int,得先dropna()或用astype('Int64')
正则里用 \d 和 [0-9] 有区别吗
在 pandas 的 str.extract 中,\d 和 [0-9] 行为基本一致,但有个关键差异:\d 在某些 Unicode 模式下可能匹配全角数字(如 '123'),而 [0-9] **严格只认 ASCII 数字字符**。
多数中文数据场景下,原始字符串里的数字都是半角,所以用哪个都行;但如果你的数据来自 OCR 或用户粘贴,混入了全角数字,\d 可能意外命中,[0-9] 更可控。
- 推荐明确写
[0-9],避免隐式 Unicode 行为 - 需要匹配负数?用
r'(-?[0-9]+\.?[0-9]*)',注意-?要放最前,且小数点后数字可选 - 开头或结尾有空格干扰?加
strip()再 extract,别指望正则自动 trim
extract 后结果是 object 类型,怎么安全转成数值
str.extract 返回的列默认是 object dtype,即使内容全是数字字符串,也不能直接参与计算。直接 .astype(float) 遇到 NaN 会报错:TypeError: cannot convert float NaN to integer。
- 稳妥做法:用
pd.to_numeric(col, errors='coerce'),把非法值(含NaN)统一转为NaN,返回float64 - 要整数且确定无小数?先
to_numeric(..., downcast='integer'),再astype('Int64')(支持 null 的整数类型) - 千万别用
astype(int)—— 它不接受NaN,哪怕只有 1 行空也会崩
为什么 extract(r'(\d+)') 对 "abc123def456" 只返回 123
因为 str.extract 是**逐行尝试匹配一次**,正则引擎从左到右扫描,找到第一个满足 (\d+) 的子串就停,不会回溯找第二个。它不是“全局提取”,而是“首匹配提取”。
这种行为和 re.search() 一致,和 re.findall() 不同。如果你看到预期外的截断,大概率是误以为它能扫完整个字符串取所有数字。
- 验证方式:对单个字符串跑
re.search(r'(\d+)', s),看 group(1) 是什么 - 真要多数字字段?提前用
str.split()或str.replace()做预处理,或者换str.extractall()(返回 MultiIndex DataFrame) -
extractall注意:结果行数可能大于原 DataFrame,后续 merge 要小心索引对齐
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











