是否有一个简单的方法来删除字符串中的多个空格?

假设这个字符串:

The   fox jumped   over    the log.

变成:

The fox jumped over the log.

在不分割和进入列表的情况下,最简单的实现方法(1-2行)是什么?

621759 次浏览
>>> import re
>>> re.sub(' +', ' ', 'The     quick brown    fox')
'The quick brown fox'
import re
s = "The   fox jumped   over    the log."
re.sub("\s\s+" , " ", s)

re.sub("\s\s+", " ", s)

因为逗号前的空格在PEP  8中被列为不能忍受的事,在评论中被列为由用户Martin Thoma提到

foo是你的字符串:

" ".join(foo.split())

需要注意的是,这将删除“所有空白字符(空格,制表符,换行符,返回,formfeed)”(感谢hhsaffar,见评论)。例如,"this is \t a test\n"将有效地结束为"this is a test"

类似于前面的解决方案,但更具体:用一个空格替换两个或多个空格:

>>> import re
>>> s = "The   fox jumped   over    the log."
>>> re.sub('\s{2,}', ' ', s)
'The fox jumped over the log.'

我不得不同意Paul McGuire的评论。对我来说,

' '.join(the_string.split())

比快速生成正则表达式要好得多。

我的测量结果(Linux和Python 2.5)显示,先分离后连接的速度几乎比“re.sub(…)”快5倍,如果你一次预编译正则表达式并多次执行该操作,速度仍然快3倍。而且无论从哪方面看,它都更容易理解——更python化。

另一个选择:

>>> import re
>>> str = 'this is a            string with    multiple spaces and    tabs'
>>> str = re.sub('[ \t]+' , ' ', str)
>>> print str
this is a string with multiple spaces and tabs

使用带“\s”的正则表达式并执行简单的string.split()将删除其他空白-如换行符、回车符、制表符。除非需要这样做,否则为了只有多个空格,我给出了这些例子。

我使用11段,1000字,6665字节的Lorem Ipsum来获得真实的时间测试,并在整个过程中使用随机长度的额外空格:

original_string = ''.join(word + (' ' * random.randint(1, 10)) for word in lorem_ipsum.split(' '))

一行程序实际上将删除任何前导/尾随空格,并保留一个前导/尾随空格(但只保留一个;-)。

# setup = '''


import re


def while_replace(string):
while '  ' in string:
string = string.replace('  ', ' ')


return string


def re_replace(string):
return re.sub(r' {2,}' , ' ', string)


def proper_join(string):
split_string = string.split(' ')


# To account for leading/trailing spaces that would simply be removed
beg = ' ' if not split_string[ 0] else ''
end = ' ' if not split_string[-1] else ''


# versus simply ' '.join(item for item in string.split(' ') if item)
return beg + ' '.join(item for item in split_string if item) + end


original_string = """Lorem    ipsum        ... no, really, it kept going...          malesuada enim feugiat.         Integer imperdiet    erat."""


assert while_replace(original_string) == re_replace(original_string) == proper_join(original_string)


#'''

# while_replace_test
new_string = original_string[:]


new_string = while_replace(new_string)


assert new_string != original_string

# re_replace_test
new_string = original_string[:]


new_string = re_replace(new_string)


assert new_string != original_string

# proper_join_test
new_string = original_string[:]


new_string = proper_join(new_string)


assert new_string != original_string

# eyz8 # eyz9;最初的方式,我这样做,while循环工作在相同的标签,original_string,因此第二次运行,将没有什么要做的。它现在的设置方式,调用一个函数,使用两个不同的标签,这不是问题。我给所有的工人添加了assert语句,以验证我们在每次迭代中都改变了一些东西(对于那些可能怀疑的人来说)。例如,改成这个,它就坏了:

# while_replace_test
new_string = original_string[:]


new_string = while_replace(new_string)


assert new_string != original_string # will break the 2nd iteration


while '  ' in original_string:
original_string = original_string.replace('  ', ' ')

Tests run on a laptop with an i5 processor running Windows 7 (64-bit).


timeit.Timer(stmt = test, setup = setup).repeat(7, 1000)


test_string = 'The   fox jumped   over\n\t    the log.' # trivial


Python 2.7.3, 32-bit, Windows
test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
while_replace_test |   0.001066 |   0.001260 |   0.001128 |   0.001092
re_replace_test |   0.003074 |   0.003941 |   0.003357 |   0.003349
proper_join_test |   0.002783 |   0.004829 |   0.003554 |   0.003035


Python 2.7.3, 64-bit, Windows
test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
while_replace_test |   0.001025 |   0.001079 |   0.001052 |   0.001051
re_replace_test |   0.003213 |   0.004512 |   0.003656 |   0.003504
proper_join_test |   0.002760 |   0.006361 |   0.004626 |   0.004600


Python 3.2.3, 32-bit, Windows
test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
while_replace_test |   0.001350 |   0.002302 |   0.001639 |   0.001357
re_replace_test |   0.006797 |   0.008107 |   0.007319 |   0.007440
proper_join_test |   0.002863 |   0.003356 |   0.003026 |   0.002975


Python 3.3.3, 64-bit, Windows
test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
while_replace_test |   0.001444 |   0.001490 |   0.001460 |   0.001459
re_replace_test |   0.011771 |   0.012598 |   0.012082 |   0.011910
proper_join_test |   0.003741 |   0.005933 |   0.004341 |   0.004009

test_string = lorem_ipsum
# Thanks to http://www.lipsum.com/
# "Generated 11 paragraphs, 1000 words, 6665 bytes of Lorem Ipsum"


Python 2.7.3, 32-bit
test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
while_replace_test |   0.342602 |   0.387803 |   0.359319 |   0.356284
re_replace_test |   0.337571 |   0.359821 |   0.348876 |   0.348006
proper_join_test |   0.381654 |   0.395349 |   0.388304 |   0.388193


Python 2.7.3, 64-bit
test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
while_replace_test |   0.227471 |   0.268340 |   0.240884 |   0.236776
re_replace_test |   0.301516 |   0.325730 |   0.308626 |   0.307852
proper_join_test |   0.358766 |   0.383736 |   0.370958 |   0.371866


Python 3.2.3, 32-bit
test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
while_replace_test |   0.438480 |   0.463380 |   0.447953 |   0.446646
re_replace_test |   0.463729 |   0.490947 |   0.472496 |   0.468778
proper_join_test |   0.397022 |   0.427817 |   0.406612 |   0.402053


Python 3.3.3, 64-bit
test |      minum |    maximum |    average |     median
---------------------+------------+------------+------------+-----------
while_replace_test |   0.284495 |   0.294025 |   0.288735 |   0.289153
re_replace_test |   0.501351 |   0.525673 |   0.511347 |   0.508467
proper_join_test |   0.422011 |   0.448736 |   0.436196 |   0.440318

对于普通字符串,while循环似乎是最快的,其次是Pythonic字符串分割/连接,regex在后面拉。

对于非平凡字符串,似乎还有更多的东西需要考虑。32位2.7 ?它是正则表达式的救星!2.7 64位?while循环是最好的。32位3.2,使用“合适的”join。64位3.3,执行while循环。一次。

最后,可以提高性能在需要的时候如果/,/,但最好是记住咒语:

  1. 让它起作用
  2. 纠正错误
  3. 快一点

IANAL, YMMV,买者自负!

一个简单的灵魂

>>> import re
>>> s="The   fox jumped   over    the log."
>>> print re.sub('\s+',' ', s)
The fox jumped over the log.
string = 'This is a             string full of spaces          and taps'
string = string.split(' ')
while '' in string:
string.remove('')
string = ' '.join(string)
print(string)

# EYZ0:

这是一个充满空格和点击的字符串

一行代码,删除句子之前、之后和内部所有多余的空格:

sentence = "  The   fox jumped   over    the log.  "
sentence = ' '.join(filter(None,sentence.split(' ')))

解释:

  1. 将整个字符串拆分为一个列表。
  2. 从列表中过滤空元素。
  3. 用一个空格重新连接剩下的元素*

*其余的元素应该是单词或带有标点符号的单词等。我没有对此进行广泛测试,但这应该是一个很好的起点。祝你一切顺利!

要去除空白,考虑开头、结尾和单词之间的额外空白,可以使用:

(?<=\s) +|^ +(?=\s)| (?= +[\n\0])

第一个or处理前导空白,第二个or处理字符串开头的前导空白,最后一个处理尾随空白。

为了证明使用,这个链接将为您提供一个测试。

https://regex101.com/r/meBYli/4

这将与re.split函数一起使用。

def unPretty(S):
# Given a dictionary, JSON, list, float, int, or even a string...
# return a string stripped of CR, LF replaced by space, with multiple spaces reduced to one.
return ' '.join(str(S).replace('\n', ' ').replace('\r', '').split())
import re
string = re.sub('[ \t\n]+', ' ', 'The     quick brown                \n\n             \t        fox')

这将删除所有的制表符,新行和多个空白与单一空白。

在某些情况下,用单个字符实例替换连续出现的每个空格字符是可取的。你可以使用带有反向引用的正则表达式来实现这一点。

(\s)\1{1,}匹配任何空格字符,后面跟着一个或多个该字符。现在,您所需要做的就是指定第一个组(\1)作为匹配的替换。

将其包装在函数中:

import re


def normalize_whitespace(string):
return re.sub(r'(\s)\1{1,}', r'\1', string)
>>> normalize_whitespace('The   fox jumped   over    the log.')
'The fox jumped over the log.'
>>> normalize_whitespace('First    line\t\t\t \n\n\nSecond    line')
'First line\t \nSecond line'

我没有深入研究其他示例,但是我刚刚创建了这个方法来合并多个连续的空格字符。

它不使用任何库,虽然它的脚本长度相对较长,但它不是一个复杂的实现:

def spaceMatcher(command):
"""
Function defined to consolidate multiple whitespace characters in
strings to a single space
"""
# Initiate index to flag if more than one consecutive character
iteration
space_match = 0
space_char = ""
for char in command:
if char == " ":
space_match += 1
space_char += " "
elif (char != " ") & (space_match > 1):
new_command = command.replace(space_char, " ")
space_match = 0
space_char = ""
elif char != " ":
space_match = 0
space_char = ""
return new_command


command = None
command = str(input("Please enter a command ->"))
print(spaceMatcher(command))
print(list(spaceMatcher(command)))

你能得到的用户生成字符串的最快速度是:

if '  ' in text:
while '  ' in text:
text = text.replace('  ', ' ')

短路使它比Pythonlarry全面的回答略快。如果你追求效率,并严格地寻找去除额外的空白,那么就选择这个单一空间的变化

你也可以在Pandas DataFrame中使用字符串分割技术,而不需要使用.apply(..),如果你需要对大量字符串快速执行操作,这是非常有用的。这是一行话:

df['message'] = (df['message'].str.split()).str.join(' ')

我尝试过下面的方法,它甚至适用于极端的情况,比如:

str1='          I   live    on    earth           '


' '.join(str1.split())

但如果你更喜欢正则表达式,它可以这样做:

re.sub('\s+', ' ', str1)

尽管必须进行一些预处理以删除尾随和结束空格。

Python开发人员的解决方案:

import re


text1 = 'Python      Exercises    Are   Challenging Exercises'
print("Original string: ", text1)
print("Without extra spaces: ", re.sub(' +', ' ', text1))
< p >输出:
原始字符串:Python练习是具有挑战性的练习 没有额外的空格:Python练习是具有挑战性的练习

令人惊讶的是,没有人发布一个简单的函数,它会比所有其他发布的解决方案快得多。是这样的:

def compactSpaces(s):
os = ""
for c in s:
if c != " " or (os and os[-1] != " "):
os += c
return os
import re


Text = " You can select below trims for removing white space!!   BR Aliakbar     "
# trims all white spaces
print('Remove all space:',re.sub(r"\s+", "", Text), sep='')
# trims left space
print('Remove leading space:', re.sub(r"^\s+", "", Text), sep='')
# trims right space
print('Remove trailing spaces:', re.sub(r"\s+$", "", Text), sep='')
# trims both
print('Remove leading and trailing spaces:', re.sub(r"^\s+|\s+$", "", Text), sep='')
# replace more than one white space in the string with one white space
print('Remove more than one space:',re.sub(' +', ' ',Text), sep='')

Result: as code

"Remove all space:Youcanselectbelowtrimsforremovingwhitespace!!BRAliakbar"
"Remove leading space:You can select below trims for removing white space!!   BR Aliakbar"
"Remove trailing spaces: You can select below trims for removing white space!!   BR Aliakbar"
"Remove leading and trailing spaces:You can select below trims for removing white space!!   BR Aliakbar"
"Remove more than one space: You can select below trims for removing white space!! BR Aliakbar"

" ".join(foo.split())对于所问的问题不太正确,因为完全也删除了单个前导和/或尾随空格。所以,如果它们也将被1个空白替换,你应该像下面这样做:

" ".join(('*' + foo + '*').split()) [1:-1]

当然,它没有那么优雅。

因为@pythonlarry问这里缺少基于生成器的版本

groupby连接很简单。Groupby将对具有相同键的连续元素进行分组。并返回每个组的键对和元素列表。所以当键是空格空格是返回整个组。

from itertools import groupby
def group_join(string):
return ''.join(' ' if chr==' ' else ''.join(times) for chr,times in groupby(string))

由变体组成的组很简单,但是很慢。现在来看发电机变体。在这里,我们使用了一个迭代器,即字符串,并生成除字符后面的字符外的所有字符。

def generator_join_generator(string):
last=False
for c in string:
if c==' ':
if not last:
last=True
yield ' '
else:
last=False
yield c


def generator_join(string):
return ''.join(generator_join_generator(string))

所以我用其他的方法测量了时间。

  • while_replace 0.015868543065153062
  • re_replace 0.22579886706080288
  • proper_join 0.40058281796518713
  • group_join 5.53206754301209
  • generator_join 1.6673167790286243

Hello和World由64KB的空格分隔

  • while_replace 2.991308711003512
  • re_replace 0.08232860406860709
  • proper_join 6.294375243945979
  • group_join 2.4320066600339487
  • generator_join 6.329648651066236

不忘原话

  • while_replace 0.002160938922315836
  • re_replace 0.008620491018518806
  • proper_join 0.005650000995956361
  • group_join 0.028368217987008393
  • generator_join 0.009435956948436797
有趣的是,对于几乎只有空格的字符串组连接并没有那么糟糕 计时显示的中位数总是七次,每次一千次

这样做,并将这样做::)

# python... 3.x
import operator
...
# line: line of text
return " ".join(filter(lambda a: operator.is_not(a, ""), line.strip().split(" ")))

这个正是你想要的

old_string = 'The   fox jumped   over    the log '
new_string = " ".join(old_string.split())
print(new_string)

将会导致

The fox jumped over the log.

最简单的解决方案!

a = 'The   fox jumped   over    the log.'
while '  ' in a: a = a.replace('  ', ' ')
print(a)

输出:

The fox jumped over the log.