2017-04-19 78 views
1

我有一个字符串,它看起来是这样的:用匹配组中的下划线替换空格字符?

"(case when Campaign='Back to School' and VariableName='Total_FB_Spend' then VariableValue else 0 end) AS Back to School_Total_FB_Spend,(case when Campaign='Back to School' and VariableName='Total_FB_Imp' then VariableValue else 0 end) AS Back to School_Total_FB_Imp"

我想使用Python正则表达式后删除在列名中的空格“端)AS”字符。结果应该成为这样的事情

"(case when Campaign='Back to School' and VariableName='Total_FB_Spend' then VariableValue else 0 end) AS Back_to_School_Total_FB_Spend,(case when Campaign='Back to School' and VariableName='Total_FB_Imp' then VariableValue else 0 end) AS Back_to_School_Total_FB_Imp"

我能够匹配那些我有兴趣在Python [example here]使用正则表达式的部分,但我想知道如何优雅地(例如,一个衬垫或在Python化方式)替换匹配的组中的空格字符。

+1

请在下面检查我的答案。请注意,虽然基于lookbehind的正则表达式在这种情况下更为优化,但我决定尽可能少地改变原始模式本身,以显示如何在单个lambda替换中处理多个*组。 –

回答

1

你需要一个re.sub用lambda表达式作为替换参数:

import re 
s = "(case when Campaign='Back to School' and VariableName='Total_FB_Spend' then VariableValue else 0 end) AS Back to School_Total_FB_Spend,(case when Campaign='Back to School' and VariableName='Total_FB_Imp' then VariableValue else 0 end) AS Back to School_Total_FB_Imp" 
pat = r'(end\) as)([^,]*)' 
print(re.sub(pat, lambda m: "{}{}".format(m.group(1), m.group(2).replace(" ", "_")), s)) 

Python demo

请注意,我用更高效的([^,]*)更换你的(.*?(,|$)),比任何零个或多个字符等,。现在,整个正则表达式匹配:

  • (end\) as) - 第1组:end) as
  • ([^,]*) - 组2:比,

然后其他任何零个或多个字符,与lambda m: "{}{}".format(m.group(1), m.group(2).replace(" ", "_")),的内容第一个捕获组被复制回结果不变,第二个组的内容被修改为.replace(" ", "_")。当然,如果可能有任何空格,你可以运行另一个正则表达式,re.sub(r'\s+', '_', m.group(2))

+0

Stribizew非常感谢你对你的建议解决方案如何在一起工作的详细解释!它像一个魅力。我最终使用're.sub(r'\ W +','_',m.group(2))',因为它更容易。我对'lambda'还不是很熟悉,所以我想知道它是如何返回匹配正则表达式模式的组(没有我们在'lambda'语句中写入任何明确的're.search(pat,s)')。如果你不介意进一步解释或者指导我一个好的资源,这就解释了我非常感谢! :) – user1330974

+0

非常感谢您的详细解释!由于患者/详细说明,您的答案非常有帮助和清晰。今天我了解到're.sub'将匹配的对象传递给'lambda'(或'lambda'捕获're.sub'中的任何匹配项)。很强大! – user1330974

+1

对不起,格式化。重新发布评论:实际上,lambda中的“m”代表一个匹配数据对象。当你使用're.sub'时,正则表达式引擎搜索模式的所有非重叠事件,并且当找到匹配时,所有的捕获组形成'.group()'。因此,'(a)|(b)'包含2个捕获组,并且当在'abc'字符串上使用时,首先找到'a'(在'm.group(1)'中使用'a',在m.group(2)')中为空(取决于Python版本)。您可以访问任何捕获组或整个匹配('m.group()'),并根据您的需要进行操作(转换为int,增量等) –

1

受@Wiktor启发的另一种解决方案。

import re 
s = "(case when Campaign='Back to School' and VariableName='Total_FB_Spend' then VariableValue else 0 end) AS Back to School_Total_FB_Spend,(case when Campaign='Back to School' and VariableName='Total_FB_Imp' then VariableValue else 0 end) AS Back to School_Total_FB_Imp" 
pat = r'(?<=end\) as)[\w\s]*(?=,)' 
print(re.sub(pat, lambda m: m.group(0).replace(" ", "_"), s, flags=re.IGNORECASE)) 

这里我们使用先行和正则表达式的回顾后功能只匹配,我们要改变的字符串。正则表达式将匹配单词字符[a-zA-Z0-9_]空格之前的任何序列end) as,然后是,。主要区别在于比赛只包含一个组。

+1

请注意,后视作为捕获组不像一个lookbehind模式应该是固定的长度。你不能在那里使用'\ s *'和'\ w +'。 –

+1

确实,但是因为我们正在寻找一个固定的后缀和后缀,所以在这种情况下这不会成为问题。 – Jonas

+0

@Jonas谢谢你的替代建议。我在这里第一次在正则表达式中学到了一些有关前瞻/后视模式的知识。当我尝试上面分享的代码时,我收到了'IndexError:no such group'。 – user1330974

相关问题