在Python中用单个空格替换多个空格

486

我有一个字符串:

mystring = 'Here is  some   text   I      wrote   '

我怎么才能将重复的双倍、三倍(......)空格字符替换为单个空格,以便得到:

mystring = 'Here is some text I wrote'

6
您可能应该说“用单个空格代替多个空白字符”,因为空白字符是一个字符类(制表符、换行符等)。 - Noufal Ibrahim
3个回答

1008

一个简单的可能性(如果你宁愿避免正则表达式)是:

' '.join(mystring.split())
分割和连接执行你明确要求的任务,而且它们还执行了额外的任务,这个你没有提到但在你的示例中可以看到,即去除尾部空格;-)。

8
哦,真酷!我曾经尝试过类似的解决方案,但是使用了split(' ')方法然后使用filter函数来移除空元素。我从未知道使用没有参数的split方法可以像这样工作。这种方法也更快,用timeit.py测试结果表明,它大约只需要0.74微秒,而正则表达式则需要5.75微秒。 - Roman
19
@Roman,是的,x.split()(和x.split(None))会根据长度为1+的空白序列(包括制表符、换行符等,就像re的\s)进行分割 - 而且速度相当快。很高兴能帮助! - Alex Martelli
12
这是一个非常优雅的解决方案,但我想提醒一下,这也会删除任何换行符。 - trudolf
3
为了避免 '\n' 与 ' ' 混淆,可以使用 splitlines() 方法来处理文本。示例如下:' '.join((''.join(text.splitlines())).split())。 - Pradeep Singh
2
只需使用 ' '.join(mystring.split(' ')) 即可仅删除连续重复的空格。这也将删除前导和尾随空格,但将保留换行符、制表符等。 - FifthAxiom
显示剩余3条评论

194

正则表达式可以用于更好地控制组合的空白字符。

要匹配Unicode空格符:

import re

_RE_COMBINE_WHITESPACE = re.compile(r"\s+")

my_str = _RE_COMBINE_WHITESPACE.sub(" ", my_str).strip()

仅匹配ASCII空格:

import re

_RE_COMBINE_WHITESPACE = re.compile(r"(?a:\s+)")
_RE_STRIP_WHITESPACE = re.compile(r"(?a:^\s+|\s+$)")

my_str = _RE_COMBINE_WHITESPACE.sub(" ", my_str)
my_str = _RE_STRIP_WHITESPACE.sub("", my_str)

在保留控制字符如x0b、x0c、x1c、x1d、x1e、x1f的情况下,仅匹配ASCII空格有时是必要的。

参考:

关于\s

对于Unicode(str)模式: 匹配Unicode空格字符(包括[ \t\n\r\f\v],以及许多其他字符,例如许多语言中规定的不间断空格)。 如果使用了ASCII标志,则仅匹配[ \t\n\r\f\v]。

关于re.ASCII

使\w、\W、\b、\B、\d、\D、\s和\S执行ASCII-only匹配,而不是完整的Unicode匹配。这仅对Unicode模式有意义,并且对字节模式不起作用。相当于内联标志(?a)。

strip()将删除任何前导和尾随空格。


24
如果你只想替换空格(' '),可以使用re.sub(' +', ' ', mystring).strip() - Simon Hessner

48

为了完整性,你也可以使用:

mystring = mystring.strip()  # the while loop will leave a trailing space, 
                  # so the trailing whitespace must be dealt with
                  # before or after the while loop
while '  ' in mystring:
    mystring = mystring.replace('  ', ' ')

在字符串中包含相对较少空格的情况下,它将比 re 更快地工作。无论哪种情况,Alex Martelli 的 split/join 解决方案 至少具有同样快的表现(通常更快)。

在您的示例中,使用 timeit.Timer.repeat() 的默认值,我得到以下时间:

str.replace: [1.4317800167340238, 1.4174888149192384, 1.4163512401715934]
re.sub:      [3.741931446594549,  3.8389395858970374, 3.973777672860706]
split/join:  [0.6530919432498195, 0.6252146571700905, 0.6346594329726258]


编辑:

刚刚看到这篇文章,它提供了这些方法的速度相对较长的比较。


比其他代码行数更多,因此不太符合“Pythonic”的风格,但更加清晰易懂。 - BuvinJ
1
提醒一下,如果您输错了,这个程序有可能会陷入无限循环的风险。 - 林果皞

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接