it-swarm.com.de

Einfache Möglichkeit, mehrere Leerzeichen in einer Zeichenfolge zu entfernen?

Angenommen, dies ist die Zeichenfolge:

The   fox jumped   over    the log.

Es würde zu:

The fox jumped over the log.

Was ist der einfachste 1-2-Liner, der dies tun kann? Ohne zu spalten und in Listen zu gehen ...

272
TIMEX
>>> import re
>>> re.sub(' +', ' ', 'The     quick brown    fox')
'The quick brown fox'
370
Josh Lee

foo ist deine Saite:

" ".join(foo.split())

Seien Sie gewarnt, obwohl "alle Leerzeichen (Leerzeichen, Tabulator, Zeilenvorschub, Zeilenumbruch, Formfeed)" entfernt werden. (Danke an hhsaffar , siehe Kommentare) dh "this is \t a test\n" wird effektiv als "this is a test" enden.

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

oder

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

da das Leerzeichen vor dem Komma in PEP8 als pet peeve aufgeführt ist, wie von Elch in den Kommentaren erwähnt.

76
Nasir

Wenn Sie reguläre Ausdrücke mit "\ s" verwenden und einfache string.split () - Befehle ausführen, werden auch andere Leerzeichen wie Zeilenumbrüche, Zeilenumbrüche und Tabulatoren entfernt. Wenn dies nicht gewünscht ist, um nur zu tun mehrere Leerzeichen, präsentiere ich diese Beispiele.


EDIT: Wie ich es gewohnt bin, habe ich darüber geschlafen und außerdem einen Tippfehler bei den letzten Ergebnissen korrigiert (v3.3.3 @ 64-bit) , nicht ​​32-bit), das Offensichtliche traf mich: Der Teststring war eher trivial.

Also bekam ich ... 11 Absätze, 1000 Wörter, 6665 Bytes von Lorem Ipsum um realistischere Zeittests zu erhalten. Anschließend habe ich durchgehend Leerzeichen in zufälliger Länge hinzugefügt:

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

Ich habe auch das "richtige join" korrigiert; Wenn es einen interessiert, wird der Einzeiler im Wesentlichen einen Streifen von führenden/nachfolgenden Leerzeichen machen, diese korrigierte Version behält ein führendes/nachfolgendes Leerzeichen bei (aber nur ONE ;-). (Ich habe das gefunden, weil der zufällig verteilte lorem_ipsum am Ende zusätzliche Leerzeichen bekam und damit den assert nicht bestanden hat.)


# 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

HINWEIS:  Die "while -Version" hat eine Kopie des original_string erstellt, da ich glaube, dass nach der Änderung beim ersten Durchlauf aufeinanderfolgende Durchläufe schneller sind (wenn auch nur ein wenig). Da dies die Zeit verlängert, habe ich diese String-Kopie zu den beiden anderen hinzugefügt, sodass die Zeiten den Unterschied nur in der Logik anzeigen. Beachten Sie, dass die Hauptinstanzen stmt auf timeit nur einmal ausgeführt werden ; So wie ich das ursprünglich getan habe, hat die while -Schleife am selben Label gearbeitet, original_string, daher gab es beim zweiten Durchlauf nichts zu tun. Die Art und Weise, wie es jetzt eingerichtet ist, eine Funktion mit zwei verschiedenen Bezeichnungen aufzurufen, ist kein Problem. Ich habe allen Arbeitern assert Anweisungen hinzugefügt, um zu überprüfen, ob wir bei jeder Iteration etwas ändern (für diejenigen, die zweifelhaft sein mögen). Zum Beispiel, ändern Sie dies und es bricht ab:

# 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

Bei der Trivial-Saite scheint eine while-Schleife die schnellste zu sein, gefolgt vom Pythonic-String-Split/Join und dem Regex, der das Heck hochzieht.

Bei nicht-trivialen Zeichenfolgen ist anscheinend noch ein bisschen mehr zu beachten. 32-Bit 2.7? Es ist Regex zur Rettung! 2.7 64-Bit? Eine while -Schleife ist am besten, mit einem guten Abstand. 32-bit 3.2, gehe mit dem "richtigen" join. 64-Bit 3.3, starten Sie eine while -Schleife. Nochmal.

Am Ende kann man die Leistung verbessern wenn/wo/wann benötigt, aber es ist immer am besten erinnere dich an das Mantra :

  1. Bring es zum Laufen
  2. Richtig machen
  3. Mach schnell

IANAL, YMMV, Vorbehalt Emptor!

48
pythonlarry

Ich muss dem oben genannten Kommentar von Paul McGuire zustimmen. Mir, 

' '.join(the_string.split())

ist dem reinen Ausreißen vorzuziehen. 

Meine Messungen (Linux, Python 2.5) zeigen, dass der Split-Then-Join fast fünfmal schneller ist als "re.sub (...)" und noch dreimal schneller, wenn Sie den Regex einmal vorkompilieren und die Operation ausführen mehrmals. Und es ist in jeder Hinsicht einfacher zu verstehen - viel mehr Pythonic.

35
Kevin Little

Ähnlich wie bei den vorherigen Lösungen, aber genauer: Ersetzen Sie zwei oder mehr Leerzeichen durch ein:

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

Eine einfache Lösung

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

Sie können die String-Aufteilungstechnik auch in einem Pandas DataFrame verwenden, ohne dass .apply (..) verwendet werden muss. Dies ist hilfreich, wenn Sie die Operation schnell an einer großen Anzahl von Strings durchführen müssen. Hier ist es in einer Zeile:

df['message'] = (df['message'].str.split()).str.join(' ')
5
devinbost
import re
string =  re.sub('[ \t\n]+', ' ', 'The     quick brown                \n\n             \t        fox')

Dadurch werden alle Registerkarten, neuen Linien und mehrere Leerräume mit einem Leerraum entfernt.

3
Rakesh Kumar

In einigen Fällen ist es wünschenswert, aufeinander folgende Vorkommen jedes Whitespace-Zeichens durch eine einzige Instanz des Zeichens that zu ersetzen. Dazu verwenden Sie einen regulären Ausdruck mit Rückreferenzen.

(\s)\1{1,} stimmt mit einem beliebigen Leerzeichen überein, gefolgt von einem oder mehreren Vorkommen dieses Zeichens. Jetzt müssen Sie nur noch die erste Gruppe (\1) als Ersatz für das Match angeben.

Dies in eine Funktion einwickeln:

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
vaultah

Eine Codezeile, um alle zusätzlichen Leerzeichen vor, nach und innerhalb eines Satzes zu entfernen: 

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

Erläuterung:

  1. Gesamte Zeichenfolge in Liste aufteilen.
  2. Leere Elemente aus der Liste filtern.
  3. Verbleibende Elemente * mit einem Leerzeichen wieder zusammenfügen 

* Die restlichen Elemente sollten Wörter oder Wörter mit Satzzeichen usw. sein. Ich habe dies nicht ausgiebig getestet, aber dies sollte ein guter Ausgangspunkt sein. Alles Gute!

2
gabchan

Andere alternative

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

Für benutzergenerierte Zeichenfolgen erhalten Sie am schnellsten:

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

Der Kurzschluss macht es etwas schneller als die umfassende Antwort von pythonlarry . Entscheiden Sie sich für Effizienz, und suchen Sie nach zusätzlichen Whitespaces der einzelnen Weltraumvariante.

1
Hassan Baig

Das scheint auch zu funktionieren:

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

Wo die Variable s Ihren String darstellt.

1
Anakimi
i have tried the following method and it even works with the extreme case 
like str1='          i   live    on    earth           '

' '.join(str1.split())

but if you prefer regular expression it can be done as:-

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

although some preprocessing has to be done in order to remove the trailing and ending space.
0
ravi tanwar

Ich habe meine einfache Methode, die am College verwendet wurde. 

line = "I     have            a       Nice    day."

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

Dadurch wird jedes doppelte Leerzeichen durch ein einzelnes Leerzeichen ersetzt und 1000 Mal ausgeführt. Das bedeutet, dass Sie 2000 zusätzliche Speicherplätze haben können und trotzdem funktionieren werden. :)

0
Zoran Bajcer

Verwenden Sie zum Entfernen von Leerzeichen unter Berücksichtigung der führenden, nachgestellten und zusätzlichen Leerzeichen zwischen Wörtern Folgendes:

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

der erste oder befasst sich mit dem führenden Leerraum, der zweite oder befasst sich mit dem Anfang des String führenden Leerraums und der letzte befasst sich mit dem nachlaufenden Leerraum

für den Verwendungsnachweis liefert dieser Link einen Test.

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

lassen Sie mich wissen, wenn Sie eine Eingabe finden, die diesen Regex-Code durchbricht.

AUCH - dies ist mit der Funktion re.split zu verwenden

0
CameronE

Wenn es sich um Whitespace handelt, das Sie mit None teilen, wird im zurückgegebenen Wert keine leere Zeichenfolge angegeben.

https://docs.python.org/2/library/stdtypes.html#str.split

0
jsnklln

Ich habe in den anderen Beispielen nicht viel gelesen, aber ich habe diese Methode gerade zur Konsolidierung mehrerer aufeinanderfolgender Leerzeichen erstellt.

Es verwendet keine Bibliotheken, und obwohl es in Bezug auf die Skriptlänge relativ lang ist, ist es keine komplexe Implementierung

def spaceMatcher(command):
    """
    function defined to consolidate multiple whitespace characters in 
    strings to a single space
    """
    #initiate index to flag if more than 1 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)))
0
Scott Anderson
string='This is a             string full of spaces          and taps'
string=string.split(' ')
while '' in string:
    string.remove('')
string=' '.join(string)
print(string)

Ergebnisse :

Dies ist eine Zeichenfolge voller Leerzeichen und Abgriffe

0