我正在尝试逐个遍历 Pandas DataFrame 的列值,以检测符合正则表达式模式的子字符串,并在其出现的任何位置替换它。DataFrame 目标列中的字符串值具有以下变体:
- ‘函数(某物)……’
- ‘func(某物,某物)……’
我尝试使用第二种变体来定位值,并用同一行中另一列的值替换逗号分隔的子字符串。
我的示例代码如下:
import re
for i, x in enumerate(df['col1']):
df.loc[i,'col2'] = re.sub(r'^(func\().+,.+(\).*)', r'\1%s\2'%(x), df.loc[i,'col2'])
*
当我将模式中的替换为 时,终端上获得了成功的输出+
:
>>> val = 'func(y,z) and func2(a,b)'
>>> val
'func(y,z) and func2(a,b)'
>>> pattern1 = r'^(func\().+,.+(\).*)'
>>> replacement = r'\1%s\2'%('x')
>>> val2 = re.sub(pattern1, replacement, val)
>>> val2
'func(x)'
>>> pattern2 = r'^(func\().+,.+(\).+)'
>>> val2 = re.sub(pattern2, replacement, val)
>>> val2
'func(x) and func2(a,b)'
>>> val3 = 'func(y) and func2(a,b)'
>>> val4 = re.sub(pattern2, replacement, val3)
>>> val4
'func(y) and func2(a, b)'
我认为.*
inpattern1
应该能够容纳最后捕获的括号后的 0 个或更多任意字符实例\)
,但至少使用.+
inpattern2
是可行的。
问题是,当我尝试在 VSCode 上使用 Python 复制 DataFrame 的列值时,我没有得到想要的输出。我想我的正则表达式模式捕获了字符串中我不想要的部分,所以得到了混合的结果。
我遗漏了什么吗pattern2
?
更新: 这是我在 VSCode 中使用的示例代码,其中结果很有希望,但是当字符串添加更多条件时,模式就不再成立。
df = pd.DataFrame({'col1':['func(a,b) and func(c,d)','func(a) and func(c)','func(b) and func(c,d)','func(a,b,c) and func(d,e,f)'],
'col2':['e','b','a','g']})
df
>>>
col1 col2
0 func(a,b) and func(c,d) e
1 func(a) and func(c) b
2 func(b) and func(c,d) a
3 func(a,b,c) and func(d,e,f) g
import re
df['col3'] = ''
for i,x in enumerate(df['col2']):
pattern = r'^(func\().+,.+(\).+)'
replacement = fr'\1{x}\2'
df.loc[i,'col3'] = re.sub(pattern,replacement,df.loc[i,'col1'])
if df.loc[i,'col3'] != df.loc[i,'col1']:
print(df.loc[i,'col1'],'--->',df.loc[i,'col3'])
>>>
func(a,b) and func(c,d) ---> func(e) and func(c,d)
func(a,b,c) and func(d,e,f) ---> func(g) and func(d,e,f)
以上是我期望看到的,但在下面的尝试中,您可以看到附加func()
条件被删除:
df = pd.DataFrame({'col1':['func(a,b) and func(c,d) and func2(z)','func(a) and func(c) and func2(z)','func(b) and func(c,d) and func2(z)','func(a,b,c) and func(d,e,f) and func2(z)'],
'col2':['e','b','a','g']})
df
>>>
col1 col2
0 func(a,b) and func(c,d) and func2(z) e
1 func(a) and func(c) and func2(z) b
2 func(b) and func(c,d) and func2(z) a
3 func(a,b,c) and func(d,e,f) and func2(z) g
import re
df['col3'] = ''
for i,x in enumerate(df['col2']):
pattern = r'^(func\().+(?:,.+)+(\).+)'
replacement = fr'\1{x}\2'
df.loc[i,'col3'] = re.sub(pattern,replacement,df.loc[i,'col1'])
if df.loc[i,'col3'] != df.loc[i,'col1']:
print(df.loc[i,'col1'],'--->',df.loc[i,'col3'])
>>>
func(a,b) and func(c,d) and func2(z) ---> func(e) and func2(z)
func(b) and func(c,d) and func2(z) ---> func(a) and func2(z)
func(a,b,c) and func(d,e,f) and func2(z) ---> func(g) and func2(z)
该模式似乎忽略了中间的func()
表达。
在将替换字符串插入
re.sub(pattern, replacement, text_string)
函数之前,请先为每次迭代准备好替换字符串。根据测试字符串和所需输出的新信息进行更新。
正则表达式模式(Python re 模块):
正则表达式演示: https://regex101.com/r/aKyQSs/4
PYTHON
输出:
正则表达式注意事项:
^
匹配字符串的开头^
。func\(
匹配文字func(
[^),]+
否定字符类[^...]
。匹配任何非文字)
或,
的字符 1 次或多次 (+
)。(
,
匹配文字,
。[^),]+
否定字符类[^...]
。匹配任何非文字)
或,
的字符 1 次或多次 (+
)。)+
匹配1次或多次(+
)。\)
匹配文字)
。问题是因为
.+
也可以匹配)
- 并且正则表达式是“贪婪的”,它会尝试匹配最长的字符串 - 所以在你的代码中.+
匹配b,c) and func(d,e,f
而不是b,c
它需要用来
[^\)]+
匹配除之外的所有内容- 因此它将在第一个而不是第二个)
停止(或者如果你有更多的话,在任何进一步的停止))
)
)
func()
完整的工作代码。
我添加了使用-loop
df.apply()
的代码for