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 ...
>>> import re
>>> re.sub(' +', ' ', 'The quick brown fox')
'The quick brown fox'
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.
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.
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 " Beachten Sie, dass die Hauptinstanzen 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.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 :
IANAL, YMMV, Vorbehalt Emptor!
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.
Ä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.'
Eine einfache Lösung
>>> import re
>>> s="The fox jumped over the log."
>>> print re.sub('\s+',' ', s)
The fox jumped over the log.
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(' ')
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.
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'
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:
* 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!
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
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() )
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.
Das scheint auch zu funktionieren:
while " " in s:
s=s.replace(" "," ")
Wo die Variable s Ihren String darstellt.
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.
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. :)
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
Wenn es sich um Whitespace handelt, das Sie mit None teilen, wird im zurückgegebenen Wert keine leere Zeichenfolge angegeben.
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)))
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