在实际数据处理场景中,经常会遇到pandas的某列包含大量非结构化文本,其中混杂着我们需要提取的P#.S#格式的值,比如产品编码中类似P123.S45、P7.S89这类符合规则的字符串,需要从中精准提取出来用于后续分析。

正则匹配规则设计
首先明确P#.S#格式的定义:以大写字母P开头,后面跟1个或多个数字,接着是点号,然后是大写字母S,后面再跟1个或多个数字。对应的正则表达式可以写为Pd+.Sd+,其中d+表示匹配1个或多个数字,.用于转义点号,避免点号被识别为正则的通配符。
pandas提取实现步骤
1. 准备测试数据
先构造包含非结构化文本的DataFrame,模拟实际场景中的杂乱数据:
import pandas as pd
# 构造测试数据,包含各种杂乱文本和符合P#.S#格式的值
data = {
"raw_text": [
"订单编号P123.S45,发货时间2024-01-01",
"产品编码为S789.P12,不符合规则",
"用户反馈P7.S89有问题,需要跟进",
"备注信息:P001.S23是旧版本编码",
"无有效编码的内容",
"多个编码P11.S22和P33.S44都在这里"
]
}
df = pd.DataFrame(data)
print(df)
2. 使用str.extract方法提取
pandas的str.extract方法可以基于正则表达式提取匹配的字符串,它会返回第一个匹配到的结果,适合单值提取的场景:
# 定义正则表达式,用括号包裹需要提取的部分 pattern = r"(Pd+.Sd+)" # 提取匹配到的值,没有匹配到的位置返回NaN df["extracted_value"] = df["raw_text"].str.extract(pattern) print(df[["raw_text", "extracted_value"]])
3. 使用str.findall方法提取多个值
如果一行文本中可能包含多个P#.S#格式的值,可以使用str.findall方法,它会返回所有匹配到的结果组成的列表:
# 提取所有匹配到的值,返回列表 df["all_extracted"] = df["raw_text"].str.findall(pattern) print(df[["raw_text", "all_extracted"]])
结果校验与异常处理
提取完成后需要对结果做校验,比如检查是否存在空值、匹配到的值是否符合预期格式:
# 检查提取结果的空值情况
null_count = df["extracted_value"].isna().sum()
print(f"未匹配到值的行数:{null_count}")
# 校验提取到的值是否符合格式(二次校验)
def check_format(val):
if pd.isna(val):
return False
import re
return bool(re.fullmatch(r"Pd+.Sd+", val))
df["is_valid"] = df["extracted_value"].apply(check_format)
print(df[["extracted_value", "is_valid"]])
注意事项
- 如果文本中的P和S可能是小写,可以在正则中添加忽略大小写参数,比如
df["raw_text"].str.extract(pattern, flags=re.IGNORECASE),同时需要提前导入re模块。 - 如果文本中的点号是全角字符,需要先做字符串替换,将点号统一转为半角,再执行提取操作。
- 如果原始列存在缺失值(NaN),pandas的字符串方法会自动跳过,返回NaN,不需要额外做空值处理。