文字列内の複数のスペースを削除する簡単な方法はありますか?


390

次の文字列を想定します。

The   fox jumped   over    the log.

に変わる:

The fox jumped over the log.

これを実現する最も簡単な(1〜2行)は何ですか?


22
リストへの嫌悪感は何ですか?これらは言語の不可欠な部分であり、 "" .join(list_of_words)は、文字列のリストをスペースで区切られた単一の文字列にするためのコアイディオムの1つです。
PaulMcG 2009年

3
@ Tom / @ Paul:単純な文字列の場合、(文字列)結合は単純で甘いでしょう。しかし、邪魔したくない他の空白がある場合は、さらに複雑になります...この場合、「while」または正規表現のソリューションが最適です。「正しい」と思われる文字列結合の下に、これを行う3つの方法の時間指定テスト結果を投稿しました。
pythonlarry

回答:


529
>>> import re
>>> re.sub(' +', ' ', 'The     quick brown    fox')
'The quick brown fox'

20
このソリューションは、単一の空白文字のみを処理します。nsr81のソリューションのように、\ sで処理されるタブやその他の空白文字は置き換えられません。
Taylor Leese

2
それは真実でstring.splitあり、あらゆる種類の空白も扱います。
Josh Lee

6
これはスペース文字にのみ焦点を当て、「\ n」のような文字には影響を与えないので、私はこれを好みます。
hhsaffar 2014年

2
はい、そうです。しかし、その前にstrip()を実行する必要があります。両端のスペースを削除します。
Hardik Patel

17
を使用re.sub(' {2,}', ' ', 'The quick brown fox')して、単一スペースの単一スペースの冗長な置換防ぐことができます。
AneesAhmed777

541

foo あなたの文字列です:

" ".join(foo.split())

これにより「すべての空白文字(スペース、タブ、改行、改行、フォームフィード)」が削除されます(hhsaffarのおかげで、コメントを参照してください)。つまり、"this is \t a test\n"実質的にになります"this is a test"


19
「リストを分割したりリストに入れたりせずに...」
ガンボ

72
「分割してリストに入れずに...」を無視したのは、それでも最良の答えだと思うからです。
テイラーリース、

1
これにより、末尾のスペースが削除されます。それらを保持したい場合:text [0:1] + "" .join(text [1:-1] .split())+ text [-1]
user984003

re.sub()ソリューションよりも6倍高速です。
nerdfever.com

1
@ AstraUvarova-Saturn'sstarプロファイリングしました。
nerdfever.com

85
import re
s = "The   fox jumped   over    the log."
re.sub("\s\s+" , " ", s)

または

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

カンマの前のスペースは、コメントでユーザーマーティントーマ述べたようにPEP 8ペットピーブとしてリストされているためです。


2
私はその正規表現をに変更しr"\s\s+"て、すでに単一のスペースを置き換えようとしないようにする傾向があります。
ベンブランク

19
その動作が必要な場合"\s{2,}"は、中程度に進んだ正規表現の動作を知らないための回避策ではなく、なぜでしょうか?
Chris Lutz、

2
sub()は入力文字列を変更せずs、新しい値を返すことに注意してください。
gcb 2013

1
@moose —パフォーマンスよりも読みやすさの最適化です。 \s+行が読み込ま「交換する原因となる1つのスペースで以上のスペースを」ではなく、「置き換える2つのスペースで以上のスペースを」。前者はすぐに立ち止まって、「なぜ1つのスペースを1つのスペースに置き換えるのですか?それはばかげています」と思います。私には、それは(非常にマイナーな)コードのにおいです。私は実際にそれがとにかく新しい文字列にコピーするために起こっているように、2つの間のすべてのパフォーマンスの違いがあることを期待していない、と関係なく、スペースがコピーされている場所の停止とテストを持っているから
Ben Blank 2015年

8
\s\s+これは、TAB文字を通常のスペースに正規化しないため、お勧めしません。スペース+タブはこの方法で置き換えられます。
vdboor 2015

51

「\ s」で正規表現を使用し、単純なstring.split()を実行すると、改行、改行、タブなどの他の空白削除されます。これが必要でない限り、複数のスペースのみを使用するために、これらの例を示します。

私が使用11の段落、1000の言葉、Loremのイプサムの6665バイトを現実的な時間テストおよび使用されるランダムな長さの余分なスペース全体を取得するには:

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

ワンライナーは基本的に、先頭/末尾のスペースのストリップを実行し、先頭/末尾のスペースを保持します(ただしONE ;-のみ)。

# 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

注: whileバージョン」はのコピーを作成しoriginal_stringました。最初の実行で変更すると、その後の実行の方が速くなると思います(少しだけ)。これにより時間が追加されたので、この文字列のコピーを他の2つに追加して、時間の違いがロジックのみで示されるようにしました。 main stmton timeitインスタンスは一度だけ実行されることに注意してください。私がこれを行った元の方法では、whileループは同じラベルで機能しましたoriginal_string。したがって、2回目の実行では、何もすることはありません。現在の設定方法、2つの異なるラベルを使用した関数の呼び出しは問題ありません。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文字列分割/結合、正規表現が後部を引き上げるように見えます。

自明ではない文字列の場合、もう少し検討すべきことがあるようです。32ビット2.7?それは救助の正規表現です!2.7 64ビット?whileループはまともなマージンにより、最高です。32ビット3.2の場合は、「proper」を使用しjoinます。64ビット3.3、whileループに行きます。再び。

最終的には、必要に応じて/場所/必要に応じてパフォーマンスを向上させることができますが、常にマントラ覚えておくことをお勧めします。

  1. 機能させる
  2. 正しくする
  3. 速くする

IANAL、YMMV、Caveat Emptor!


1
' '.join(the_string.split())これは通常の使用例であるため、単純なものをテストしていただければ幸いですが、作業に感謝します!
wedi

@wedi:他のコメント(Gumbo ; user984003など)によると、彼女/彼の解決策は推定であり、「すべての場合に」機能しません)、この種の解決策は質問者の要求に準拠していません。.split( '')とcomp / genを使用することもできますが、先頭/末尾のスペースを処理するのが難しくなります。
pythonlarry 2014年

@wedi:例:' '.join(p for p in s.split(' ') if p)<-まだ先頭/末尾のスペースが失われていますが、複数のスペースが含まれています。それらを維持するには、次のようにする必要がありますparts = s.split(' '); (' ' if not parts[0] else '') + ' '.join(p for p in s.split(' ') if p) + (' ' if not parts[-1] else '')
pythonlarry 2014年

マントラをありがとう@pythonlarry!詳細なテストが大好きです!6年経ってから、あなたの考えや見方が変わったかどうか知りたいです。
JayRizzo

ジェネレーターを使用するバージョンがありません
Lee

42

Paul McGuireのコメントに同意する必要があります。私に、

' '.join(the_string.split())

正規表現を打ち消すよりもはるかに好ましい。

私の測定(LinuxおよびPython 2.5)は、split-then-joinが "re.sub(...)"を実行する場合よりも約5倍速く、正規表現を1回プリコンパイルして操作を実行した場合でも3倍速いことを示しています。複数回。そして、それは理解しやすい任意の措置によってである- ずっとよりPython的。


これにより、末尾のスペースが削除されます。それらを保持したい場合:text [0:1] + "" .join(text [1:-1] .split())+ text [-1]
user984003

4
単純な正規表現の方が読みやすいです。必要になる前にパフォーマンスを最適化しないでください。
gcb 2013

@gcb:なぜ駄目なのですか?(たとえば、需要が高いために)高スループットのシナリオを期待している場合はどうなりますか?そのシナリオで、最初からリソースの消費が少ないと予想されるものを展開してみませんか?
Hassan Baig 2018

1
@HassanBaigすでにパフォーマンス要件がある場合、それは本当に時期尚早の最適化ではありませんよね?私のポイントは、まだパフォーマンスにこだわる必要がない場合です。常に、読みやすさを目指した方がよいでしょう。
gcb 2018年

14

以前のソリューションに似ていますが、より具体的です。2つ以上のスペースを1つに置き換えます。

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

11

シンプルな魂

>>> import re
>>> s="The   fox jumped   over    the log."
>>> print re.sub('\s+',' ', s)
The fox jumped over the log.

6

.apply(..)を使用せずにPandas DataFrameで文字列分割手法を使用することもできます。これは、多数の文字列に対して操作をすばやく実行する必要がある場合に便利です。ここでは1行です。

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

6
import re
string = re.sub('[ \t\n]+', ' ', 'The     quick brown                \n\n             \t        fox')

これにより、すべてのタブ、新しい行、および単一の空白を含む複数の空白が削除されます。


ただし、 '\ x00'から '\ x0020'のような範囲内にない空白文字(印刷不可)がある場合、コードはそれらを削除しません。
Muskovets

5

私は次の方法を試しましたが、それは次のような極端なケースでも機能します:

str1='          I   live    on    earth           '

' '.join(str1.split())

ただし、正規表現を使用する場合は、次のように実行できます。

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

末尾と末尾のスペースを削除するには、いくつかの前処理を行う必要があります。


3

これも機能するようです:

while "  " in s:
    s = s.replace("  ", " ")

変数がs文字列を表す場所。


2

場合によっては、連続するすべての空白文字を、その文字の単一のインスタンスで置き換えることが望ましい場合があります。これを行うには、後方参照付きの正規表現を使用します。

(\s)\1{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'

2

別の選択肢:

>>> 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

2

文の前後および文内のすべての余分なスペースを削除する1行のコード:

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

説明:

  1. 文字列全体をリストに分割します。
  2. リストから空の要素をフィルタリングします。
  3. 残りの要素を1つのスペースで再結合します*

*残りの要素は単語または句読点のある単語などにする必要があります。これについては十分にテストしていませんが、これは良い出発点になるはずです。ではごきげんよう!


2

Python開発者向けのソリューション:

import re

text1 = 'Python      Exercises    Are   Challenging Exercises'
print("Original string: ", text1)
print("Without extra spaces: ", re.sub(' +', ' ', text1))

出力:
Original string: Python Exercises Are Challenging Exercises Without extra spaces: Python Exercises Are Challenging Exercises


1
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())

1

ユーザーが生成した文字列で取得できる最速は次のとおりです。

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

短絡により、pythonlarryの包括的な回答よりもわずかに速くなります。効率性を重視し、シングルスペースバリエーションの余分な空白厳密に除外する場合は、この方法を使用してください。


1

まったく驚くべきこと-投稿された他のすべてのソリューションよりもはるかに高速になる単純な関数を投稿した人はいません。ここに行く:

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


0
string = 'This is a             string full of spaces          and taps'
string = string.split(' ')
while '' in string:
    string.remove('')
string = ' '.join(string)
print(string)

結果

これはスペースとタップでいっぱいの文字列です


0

単語間の先頭、末尾、余分な空白を考慮して空白を削除するには、次を使用します。

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

1つ目orは先頭の空白をor扱い、2つ目は文字列の先頭の空白を扱い、最後の1つは末尾の空白を扱います。

使用を証明するために、このリンクからテストを提供します。

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

これはre.split関数で使用されます。


0

私は大学で使用した簡単な方法を持っています。

line = "I     have            a       nice    day."

end = 1000
while end != 0:
    line.replace("  ", " ")
    end -= 1

これにより、すべての2つのスペースが1つのスペースに置き換えられ、1000回実行されます。つまり、2000の追加スペースを確保でき、引き続き機能します。:)


これは、(実質的に)アナキミの回答(2年以上前に投稿されたもの)と同じです。
Peter Mortensen

0

私は分割せずに簡単な方法を持っています:

a = "Lorem   Ipsum Darum     Diesrum!"
while True:
    count = a.find("  ")
    if count > 0:
        a = a.replace("  ", " ")
        count = a.find("  ")
        continue
    else:
        break

print(a)

1
これは、Anakimiの回答(3年以上前に投稿されたもの)とどう違うのですか?より複雑なバージョンではないですか?
Peter Mortensen

0
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='') 

結果:

すべてのスペースを削除:ホワイトスペースを削除するために以下のトリムを選択できます!! BRAliakbar先頭のスペースを削除:空白を削除するためにトリムの下を選択できます!! BR Aliakbar
後続スペースの削除:空白を削除するためにトリムの下を選択できます!! BR Aliakbar先頭と末尾のスペースを削除します:空白を削除するためにトリムの下を選択できます!! BR Aliakbar複数のスペースを削除:空白を削除するために、トリムの下を選択できます!! BRアリアクバル


-1

他の例についてはあまり読んでいませんが、連続する複数のスペース文字を統合するためのこのメソッドを作成しました。

ライブラリは使用せず、スクリプトの長さの点では比較的長いですが、複雑な実装ではありません。

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)))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.