Python正则表达式:如何实现这种复杂的替换规则?

时间:2018-03-14 12:37:53

标签: python regex re-python

我正在处理长字符串,我需要用''替换相邻句号.和/或冒号:的所有组合,但仅限于它们不相邻时到任何空白。例子:

  • a.bcd应该abcd
  • a..::.:::.:bcde.....:fg应该abcdefg
  • a.b.c.d.e.f.g.h应该abcdefgh
  • a .b应该提供a .b,因为此处的.与其左侧的空白相邻,因此无法替换
  • a..::.:::.:bcde.. ...:fg出于同样的原因应该abcde.. ...:fg

嗯,这是我尝试的(没有任何成功)。

尝试1:

s1 = r'a.b.c.d.e.f.g.h'
re.sub(re.search(r'[^\s.:]+([.:]+)[^\s.:]+', s1).group(1), r'', s1)

我希望获得'abcdefgh',但实际得到的是r''。我理解为什么:代码

re.search(r'[^\s.:]+([.:]+)[^\s.:]+', s1).group(1)

返回'.'而不是'\.',因此re.search无法理解它必须替换单个句号.而不是'.'像通常的正则表达式。

尝试2:

s1 = r'a.b.c.d.e.f.g.h'
re.sub(r'([^\s.:]*\S)[.:]+(\S[^\s.:]*)', r'\g<1>\g<2>', s1)

这不起作用,因为它返回a.b.c.d.e.f.gh

尝试3:

s1 = r'a.b.c.d.e.f.g.h'
re.sub(r'([^\s.:]*)[.:]+([^\s.:]*)', r'\g<1>\g<2>', s1)

这适用于s1,但它无法解决我的问题,因为在s2 = r'a .b'它会返回a b而不是a .b

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

这里有很多问题。你的正则表达式与你想匹配的东西不匹配;此外,您对re.subre.search的理解已经结束。

要找到某些内容,re.search可让您找到字符串中发生某些事情的位置。

替换某些内容,请在同一正则表达式而不是 re.sub上使用re.search,而不是。

并且,了解re.sub(r'thing(moo)other', '', s1)用替换字符串替换整个匹配

有了这个,你的正则表达式,听起来像你想要的

r'(?<![\s.:])[.:]+(?![\s.:])'   # updated from comments, thanks!

包含一个带有句号和冒号的字符类(请注意方括号内不需要反斜杠 - 这是一个上下文,其中点和冒号没有任何特殊含义 1 ),尽可能多次重复;双方都认为,当两边都有空格\s时,我们无法匹配这些字符,也不包括字符本身,因此正则表达式引擎无法通过应用{{找到匹配项1}}不那么严格(如果有办法的话,最好找到匹配)。

现在,正则表达式只匹配您想要实际替换的部分,因此您可以执行

+

虽然在更广泛的方案中,你还需要知道如何保留比赛的某些部分。为了演示的目的,我将使用一个正则表达式,它将点或冒号前后的文本捕获到带括号的组中:

>>> import re
>>> s1 = 'name.surname@domain.com'
>>> re.sub(r'(?<![\s.:])[.:]+(?![\s.:])', r'', s1)
'namesurname@domaincom'

查看替换字符串中的>>> re.sub(r'(.*\S)[.:]+(\S.*)', r'\g<1>\g<2>', s1) 'name.surname@domaincom' 如何引用&#34;无论第一组括号匹配&#34;并且类似\g<1>到第二个带括号的组。

您还会注意到,这无法替换第一个句点,因为第一组括号内的\g<2>匹配尽可能多的字符串。要避免这种情况,您需要一个只能尽可能少匹配的正则表达式。我们已经通过外观解决了上述问题,所以我会把你留在这里,尽管以不同的方式解决这个问题会很有趣(但并不太难)。

1 您甚至可以说正常的正则表达式语言(或语法,符号或形式)与方括号内的语言(或语法,符号或形式)分开! / p>