Python正则表达式:如何实现这个复杂的替换规则?
Python regex: how to achieve this complex replacement rule?
我正在处理长字符串,我需要用 ''
替换相邻句号 .
and/or 冒号 :
的所有组合,但仅当它们不与任何空白相邻。示例:
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)
returns '.'
而不是 '\.'
,因此 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)
这不起作用 returns 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'
它 returns a b
而不是 a .b
。
有什么建议吗?
这里有多个问题。您的正则表达式与您想要匹配的内容不匹配;而且,你对 re.sub
和 re.search
的理解是错误的。
要查找内容,re.search
可让您查找字符串中出现内容的位置。
要替换那个东西,在同一个正则表达式上使用re.sub
而不是 re.search
,不是还有。
并且,了解 re.sub(r'thing(moo)other', '', s1)
将 整个匹配项 替换为替换字符串。
除此之外,对于您的正则表达式,听起来您想要
r'(?<![\s.:])[.:]+(?![\s.:])' # updated from comments, thanks!
包含一个带有句号和冒号的字符 class(注意方括号内不需要反斜杠——这是一个点和冒号没有任何特殊含义的上下文1),尽可能重复多次;和环顾四周说我们不能匹配这些字符当有空格 \s
在任何一方,并且还排除字符本身,以便正则表达式引擎无法通过应用 [= 来找到匹配项20=] 不太严格(如果有办法,它会尽最大努力找到匹配项)。
现在,正则表达式只匹配您要实际替换的部分,因此您可以这样做
>>> 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'
查看替换字符串中的 \g<1>
如何引用回 "whatever the first set of parentheses matched" 以及类似地 \g<2>
引用第二个带括号的组。
您还会注意到,这未能替换第一个句号,因为第一组括号内的 .*
匹配了尽可能多的字符串。为避免这种情况,您需要一个只匹配尽可能少的正则表达式。我们已经用环顾四周解决了上面的问题,所以我会把你留在这里,尽管以不同的方式解决这个问题会很有趣(但也不太难)。
1 你甚至可以说普通的正则表达式语言(或语法、符号或形式主义)与语言(或语法、符号或形式主义)是分开的方括号内!
我正在处理长字符串,我需要用 ''
替换相邻句号 .
and/or 冒号 :
的所有组合,但仅当它们不与任何空白相邻。示例:
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)
returns '.'
而不是 '\.'
,因此 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)
这不起作用 returns 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'
它 returns a b
而不是 a .b
。
有什么建议吗?
这里有多个问题。您的正则表达式与您想要匹配的内容不匹配;而且,你对 re.sub
和 re.search
的理解是错误的。
要查找内容,re.search
可让您查找字符串中出现内容的位置。
要替换那个东西,在同一个正则表达式上使用re.sub
而不是 re.search
,不是还有。
并且,了解 re.sub(r'thing(moo)other', '', s1)
将 整个匹配项 替换为替换字符串。
除此之外,对于您的正则表达式,听起来您想要
r'(?<![\s.:])[.:]+(?![\s.:])' # updated from comments, thanks!
包含一个带有句号和冒号的字符 class(注意方括号内不需要反斜杠——这是一个点和冒号没有任何特殊含义的上下文1),尽可能重复多次;和环顾四周说我们不能匹配这些字符当有空格 \s
在任何一方,并且还排除字符本身,以便正则表达式引擎无法通过应用 [= 来找到匹配项20=] 不太严格(如果有办法,它会尽最大努力找到匹配项)。
现在,正则表达式只匹配您要实际替换的部分,因此您可以这样做
>>> 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'
查看替换字符串中的 \g<1>
如何引用回 "whatever the first set of parentheses matched" 以及类似地 \g<2>
引用第二个带括号的组。
您还会注意到,这未能替换第一个句号,因为第一组括号内的 .*
匹配了尽可能多的字符串。为避免这种情况,您需要一个只匹配尽可能少的正则表达式。我们已经用环顾四周解决了上面的问题,所以我会把你留在这里,尽管以不同的方式解决这个问题会很有趣(但也不太难)。
1 你甚至可以说普通的正则表达式语言(或语法、符号或形式主义)与语言(或语法、符号或形式主义)是分开的方括号内!