移除子字符串时,最好的正则表达式(在Python中)在结果中没有双空格?

移除子字符串时,最好的正则表达式(在Python中)在结果中没有双空格?,python,regex,Python,Regex,我试图在Python中使用正则表达式删除一个子字符串 子字符串可以是整个字符串,在开始时,在中间,或者在结尾。 目标是生成的字符串不应该在存在子字符串的地方有额外的空格 你能推荐一个简单有效的正则表达式来实现这一点吗 以下是场景的示例*,以及我的预期结果: 'before remove after' --> 'before after' (separated by single space) 'remove after' --> 'after' (

我试图在Python中使用正则表达式删除一个子字符串

子字符串可以是整个字符串,在开始时,在中间,或者在结尾。

目标是生成的字符串不应该在存在子字符串的地方有额外的空格

你能推荐一个简单有效的正则表达式来实现这一点吗

以下是场景的示例*,以及我的预期结果:

  'before remove after' --> 'before after' (separated by single space)
  'remove after'        --> 'after'        (no space)
  'before remove'       --> 'before'       (no space)
  'remove'              --> ''             (no space, empty string)
*before、remove和after本身可能在内部包含任何字符字母、数字、空格等

正则表达式应实现以下目标:

如果子字符串之前和之后有文本,则这两部分应该用一个空格分隔。 如果子字符串之前只有文本,则结果的结尾不应有空格。 如果子字符串后只有文本,则结果的开头不应有空格。 如果子字符串前后没有文本,则结果应为空字符串。 以下是我的几次尝试,但我无法让所有场景都正常工作

  import re

  s1 = 'before remove after'
  s2 = 'remove after'
  s3 = 'before remove'
  s4 = 'remove'

  # (1) Just replace with empty string ''...

  re.sub(r'remove', '', s1)
  'before  after'  # <-- bad (two spaces in result)

  re.sub(r'remove', '', s2)
  ' after'         # <-- bad (space in the beginning)

  re.sub(r'remove', '', s3)
  'before '        # <-- bad (space at the end)

  re.sub(r'remove', '', s4)
  ''               # <-- good (empty string)

  # (2) Capture the "before" part excluding space suffixes,
  #     capture the "after" part excluding space prefixes,
  #     and recombine them with a single space...

  re.sub(r'(.*?)\s*remove\s*(.*?)', '\\1 \\2', s1)
  'before after'   # <-- good (single space)

  re.sub(r'(.*?)\s*remove\s*(.*?)', '\\1 \\2', s2)
  ' after'         # <-- bad (space in the beginning)

  re.sub(r'(.*?)\s*remove\s*(.*?)', '\\1 \\2', s3)
  'before '        # <-- bad (space at the end)

  re.sub(r'(.*?)\s*remove\s*(.*?)', '\\1 \\2', s4)
  ' '              # <-- bad (should be an empty string)

也许你可以这样做:

进口稀土 strs=['before remove after','remove after','before remove','remove'] 对于STR中的s: s=s。替换“移除”, s=re.subr'\s+','',s.strip 打印“+s+” 它输出:

"before after"
"after"
"before"
""
试试这个:

import re

s ='before remove after'
s1 = 'remove after'    
s2 = 'before remove' 
s3 = 'remove'

print(re.sub(r"(remove\s?)|(\sremove)","",s))
print(re.sub(r"(remove\s?)|(\sremove)","",s1))
print(re.sub(r"(remove\s?)|(\sremove)","",s2))
print(re.sub(r"(remove\s?)|(\sremove)","",s3))

这将产生您要查找的结果:remove\s*|\s*remove


使用没有lambda的模式,可以在替换中使用捕获组。当remove被单词包围时,该组应包含一个空格;当remove被可选空格包围时,该组应包含一个空字符串

(?:(?<=\S)( )+)? *remove *(?(1) (?=\S)(?!remove\b))
在单引号之间输出以显示空字符串

before remove after' ==> 'before after'
'remove after' ==> 'after'
' remove' ==> ''
'remove ' ==> ''
' remove ' ==> ''
'before remove' ==> 'before'
'remove' ==> ''
'before   remove   after' ==> 'before after'
'before remove     after remove before' ==> 'before after before'
'before remove after remove before remove' ==> 'before after before'
'before remove after remove before   remove   ' ==> 'before after before'
'after remove before before remove   remove remove' ==> 'after before before'
'remove remove    remove   ' ==> ''

如果要匹配可能也与换行符匹配的空白字符,可以使用\s而不是空格

如果要匹配不带换行符的空格字符,而不是只匹配空格,可以使用[^\S\r\n]


这就完成了任务,但我想知道是否有一个正则表达式可以同时实现s.replace和re.sub步骤?请查看@aziz k'h的答案,我认为这就是您需要的。非常简单和优雅。我在试着理解它为什么会起作用?。。。在删除时匹配,结尾处为零或一个空格;这将涵盖场景1、2和4。否则,在移除时与前面的一个空格匹配;这将涵盖场景3。我的解释正确吗?有理由使用吗?而不是+?@PJSingh删除\s?仅适用于2和4。另一方面,\s删除将覆盖1和3以及的秘密,这是因为逐个字符重新测试字符串,在第一种情况下\s变为删除的r字符之前。我为什么要用?而不是+,如你所知,+表示1或更多,并且?我用的是0还是1?为了同时涵盖2和4,否则我将使用类似于remove\s | \sremove | remove的方法,我希望这对您有所帮助。这是一种很好的方法,在输入中有零或一个空格时,它可以始终如一地工作。Moritz的解决方案与此类似,但在场景2和场景3中使用*来处理额外的空间。这两种解决方案都适用于所提出的问题。我认为如果没有括号,remove\s*|\s*remove也适用。我可以理解为什么这适用于场景1、2和4。为什么它也适用于场景3 s3='before remove'?在场景3中,or remove\s*的第一部分不是首先匹配的吗,这会给我们一个结果before,并在末尾加一个空格?是的,您可以删除代码部分中已删除的括号。关于第三个案子的问题问得好。我不是100%知道它为什么有效,但它确实有效。有趣的是,在场景2中,当我切换它并使用\sremove | remove\s时,我在after前面得到了一个多余的空间。这与aziz k'h建议的答案类似。两者都简洁典雅。但是,当输入有额外的空格时,使用\s*而不是\s?具有适用于场景2和3的优点,例如s2='remove after'或s3='before remove'。请注意,这两种解决方案都不能很好地处理带有额外空格的场景1和4,例如s1='before remove after'或s4='remove'。尽管如此,使用\s*还是提供了一点额外的灵活性。如果有多个空格,则输出应该是什么?理想情况下,我希望在“一个空格”之后看到before,在“无空格”之后看到before,在“无空格”之前看到before,在“无空格”之前看到before,并且无论分隔初始字符串的部分的空格数是多少,都没有空格,但在我的问题中,这一点我还不够清楚。下面的解决方案在这方面做得非常好,除非输入像“remove”。然而,我真的想要一个不依赖lambda的纯正则表达式解决方案。我已经更新了答案,在替换中使用捕获组,而不是lambda。Moritz和aziz k'h建议的解决方案对于简单的情况是有效的,当有一个单独的空间分隔 输入刺痛。从上面的字符串列表可以看出,此解决方案涵盖了非常广泛的输入。这个稍微复杂一点的正则表达式r?:?
import re

strings = [
    'before remove after',
    'remove after',
    ' remove',
    'remove ',
    ' remove ',
    'before remove',
    'remove',
    'before   remove   after',
    'before remove     after remove before',
    'before remove after remove before remove',
    'before remove after remove before   remove   ',
    'after remove before before remove   remove remove',
    'remove remove    remove   '
]
pattern = r"(?:(?<=\S)( )+)? *remove *(?(1) (?=\S)(?!remove\b))"
for s in strings:
    print("'{0}' ==> '{1}'".format(s, re.sub(pattern, r"\1", s)))
before remove after' ==> 'before after'
'remove after' ==> 'after'
' remove' ==> ''
'remove ' ==> ''
' remove ' ==> ''
'before remove' ==> 'before'
'remove' ==> ''
'before   remove   after' ==> 'before after'
'before remove     after remove before' ==> 'before after before'
'before remove after remove before remove' ==> 'before after before'
'before remove after remove before   remove   ' ==> 'before after before'
'after remove before before remove   remove remove' ==> 'after before before'
'remove remove    remove   ' ==> ''