本节聚焦字符串的检索、条件判断与替换方法,常与布尔索引结合完成数据筛选和清洗。


1. 包含判断:str.contains()

检查每个字符串是否包含指定模式,返回布尔 Series。

基本用法

s = pd.Series(['apple pie', 'banana bread', 'cherry cake', None])
 
s.str.contains('an')
# 0    False
# 1     True
# 2    False
# 3      NaN

参数

参数说明
pat要匹配的模式(字符串或正则)
case是否区分大小写(默认 True)
flags正则标志位(如 re.IGNORECASE)
na缺失值填充值:默认 NaN,可设为 False / True
regex是否将 pat 当正则表达式(默认 True)

正则与大小写

# 忽略大小写
s.str.contains('APPLE', case=False)
 
# 正则模式:以 a 开头或包含数字
s.str.contains('^a|\d', regex=True)
 
# 字面模式:不解释为正则
s.str.contains('a.c', regex=False)
 
# 缺失值处理为 False
s.str.contains('an', na=False)
 
# 使用正则标志位
import re
s.str.contains('apple', flags=re.IGNORECASE)

与布尔索引结合

df = pd.DataFrame({'商品': ['iPhone 15', 'iPad Air', 'MacBook'], '价格': [5999, 3499, 8999]})
 
# 筛选包含 'iPhone' 或 'Mac' 的商品
df[df['商品'].str.contains('iPhone|Mac', na=False)]
 
# 筛选以 'i' 开头的商品
df[df['商品'].str.startswith('i')]

注意

在 pandas 2.x 中,regex 参数必须显式指定,不再自动推断。


2. 前缀与后缀判断

str.startswith()

s = pd.Series(['apple', 'banana', 'avocado'])
 
s.str.startswith('a')
# 0     True
# 1    False
# 2     True

str.endswith()

s.str.endswith('e')
# 0     True
# 1    False
# 2    False

组合筛选

# 筛选邮箱为 .com 或 .org 结尾
df['邮箱'].str.endswith(('.com', '.org'), na=False)
方法说明
na缺失值处理(默认 NaN)

3. 全匹配判断:str.match() / str.fullmatch()

str.match()

检查字符串开头是否匹配正则模式。

s = pd.Series(['abc123', 'xyz789', 'abc456'])
 
s.str.match('abc')
# 0     True
# 1    False
# 2     True

str.fullmatch()

要求整个字符串完全匹配正则模式(pandas 2.x 新增)。

s.str.fullmatch(r'\d+')
# 0    False
# 1    False
# 2    False(全数字才为 True)

match vs contains

  • str.match:从头匹配(等价于 re.match)
  • str.contains:包含即可(等价于 re.search)
  • str.fullmatch:完全匹配

4. 替换:str.replace()

字面替换

s = pd.Series(['apple orange', 'banana apple', 'cherry'])
 
s.str.replace('apple', 'pineapple', regex=False)
# 0    pineapple orange
# 1    banana pineapple
# 2              cherry

正则替换

# 将所有数字替换为 #
s = pd.Series(['订单 A1001', '订单 B2002'])
s.str.replace(r'\d', '#', regex=True)
# 0    订单 A####
# 1    订单 B####
 
# 删除所有非字母数字字符
s.str.replace(r'[^a-zA-Z0-9]', '', regex=True)

使用捕获组

s = pd.Series(['2024-01-15', '2025-06-30'])
 
# 将日期格式从 YYYY-MM-DD 转换为 DD/MM/YYYY
s.str.replace(r'(\d{4})-(\d{2})-(\d{2})', r'\3/\2/\1', regex=True)
# 0    15/01/2024
# 1    30/06/2025

参数

参数说明
pat查找的模式(字符串或正则)
repl替换内容,可包含捕获组 \1
case是否区分大小写
flags正则标志
regex是否为正则(pandas 2.x 必须显式)
n最大替换次数(-1 表示全部替换)
# 仅替换第一个匹配
s.str.replace('a', 'X', n=1, regex=False)

注意

  • str.replace 的 case 参数只对 regex=True(默认)生效
  • 替换为函数(高级用法):repl 可传入可调用对象,对每个匹配执行函数
import re
s.str.replace(r'\d+', lambda m: str(int(m.group()) * 2), regex=True)

5. 删除前缀/后缀:str.removeprefix() / str.removesuffix()

pandas 2.x 新增,基于 Python 3.9 的字符串方法。

s = pd.Series(['pre_apple', 'pre_banana'])
 
s.str.removeprefix('pre_')
# 0    apple
# 1    banana
 
s2 = pd.Series(['file.csv', 'data.csv'])
s2.str.removesuffix('.csv')
# 0    file
# 1    data

与 replace 的区别

  • removeprefix 只去除开头的完全匹配
  • removesuffix 只去除末尾的完全匹配
  • 更安全、语义更清晰

6. 综合筛选示例

df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '电话': ['138-0000-0000', '400-800-8888', '010-12345678'],
    '邮箱': ['zhang@test.com', 'li@test.org', None]
})
 
# 筛选手机号(1 开头,11 位数字的变形)
df[df['电话'].str.startswith('138', na=False)]
 
# 筛选企业邮箱(非个人邮箱域名)
df[df['邮箱'].str.endswith('.com', na=False)]
 
# 筛选中包含数字的姓名
df[df['姓名'].str.contains(r'\d', regex=True, na=False)]
 
# 统一替换为规范格式
df['电话_清理'] = df['电话'].str.replace(r'[^0-9]', '', regex=True)

小结

  • 判断:contains、startswith、endswith、match、fullmatch
  • 替换:replace(字面/正则/捕获组/函数)
  • 删除:removeprefix、removesuffix
  • 与布尔索引结合完成筛选:df[df['col'].str.contains(...)]