You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas正则替换疑问:为何否定式正则表达式不生效?

正则否定式不生效的原因及解决方案

问题背景

原始DataFrame定义:

import pandas as pd
df = pd.DataFrame(['0123_GRP_LE_BNS', 'ABC_GRP_BNS', 'DEF_GRP', '456A_GRP_SSA'], columns=['P'])

输出如下:

P
0  0123_GRP_LE_BNS
1      ABC_GRP_BNS
2          DEF_GRP
3     456A_GRP_SSA

需求:

  • 若字符串包含GRP_LE,则保留到GRP_LE,移除后续所有字符;
  • 若GRP后不是_LE,则保留到GRP,移除后续所有字符。

期望输出:

0     0123_GRP_LE
1         ABC_GRP
2         DEF_GRP
3        456A_GRP

尝试以下正则替换后结果不符合预期:

df['P'].replace({r'(.*_GRP)[^_LE].*':r'\1', r'(.*GRP_LE)_.*':r'\1'}, regex=True)

输出结果:

0     0123_GRP_LE
1     ABC_GRP_BNS
2         DEF_GRP
3    456A_GRP_SSA
Name: P, dtype: object

原因分析

你写的正则r'(.*_GRP)[^_LE].*'中的[^_LE]是单个字符的否定字符类,它的作用是匹配任意一个不是_、L、E的字符。

但目标字符串ABC_GRP_BNS中,GRP后面紧跟的是_,这个_属于[^_LE]排除的字符(字符类明确排除了_),所以[^_LE]无法匹配这个_,导致整个正则表达式不匹配该字符串,自然不会执行替换操作。

你真正需要的是判断GRP后面是否不是_LE这个完整序列,这需要用负向预查(零宽断言),而非单个字符的否定。

正确解决方案

方案1:分规则处理(先匹配GRP_LE,再匹配GRP后非_LE的情况)

使用负向预查(?!_LE)来判断GRP后面是否不是_LE:

df['P'].replace({
    r'(.*GRP_LE)_.*': r'\1',  # 保留GRP_LE,移除后续字符
    r'(.*GRP)(?!_LE).*': r'\1'  # GRP后不是_LE时,保留GRP,移除后续字符
}, regex=True)

方案2:单正则匹配所有情况

通过捕获组同时处理两种场景:

df['P'].replace(r'(.*GRP)(_LE)?.*', r'\1\2', regex=True)

两种方案运行后都能得到期望输出:

0    0123_GRP_LE
1        ABC_GRP
2        DEF_GRP
3       456A_GRP
Name: P, dtype: object

内容的提问来源于stack exchange,提问作者techie11

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 00:45:36