Nehmen wir diese Zeichenfolge an:
The fox jumped over the log.
Verwandlung in:
The fox jumped over the log.
Was ist die einfachste (1-2 Zeilen), um dies zu erreichen, ohne zu spalten und in Listen zu gehen?
Nehmen wir diese Zeichenfolge an:
The fox jumped over the log.
Verwandlung in:
The fox jumped over the log.
Was ist die einfachste (1-2 Zeilen), um dies zu erreichen, ohne zu spalten und in Listen zu gehen?
foo
ist Ihre Zeichenkette:
" ".join(foo.split())
Seien Sie jedoch gewarnt, dass dadurch "alle Leerzeichen (Leerzeichen, Tabulator, Zeilenumbruch, Return, Formfeed)" entfernt werden (Dank an hhsaffar (siehe Kommentare). D.h., "this is \t a test\n"
wird effektiv enden als "this is a test"
.
import re
s = "The fox jumped over the log."
re.sub("\s\s+" , " ", s)
o
re.sub("\s\s+", " ", s)
da das Leerzeichen vor dem Komma als Lieblingsärgernis in PEP 8 als vom Benutzer erwähnt Martin Thoma in den Kommentaren.
Verwendung von Regexen mit " \s " und einfache string.split()'s werden auch andere Leerzeichen - wie Zeilenumbrüche, Absatzende, Tabulatoren - entfernen. Wenn dies nicht erwünscht ist, sollten Sie nur faire mehrere Räume stelle ich diese Beispiele vor.
Ich habe 11 Absätze, 1000 Wörter, 6665 Bytes Lorem Ipsum um realistische Zeittests zu erhalten, und verwendete durchgehend zusätzliche Leerzeichen von zufälliger Länge:
original_string = ''.join(word + (' ' * random.randint(1, 10)) for word in lorem_ipsum.split(' '))
Der Einzeiler entfernt im Wesentlichen alle führenden/nachfolgenden Leerzeichen und behält ein führendes/nachfolgendes Leerzeichen bei (aber nur 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
HINWEIS: Die " Denken Sie daran, dass die wichtigsten while
Version" hat eine Kopie der original_string
denn ich glaube, dass nach einer Änderung beim ersten Durchlauf die folgenden Durchläufe schneller werden (wenn auch nur um ein bisschen). Da dies Zeit kostet, habe ich diese Kopie der Zeichenkette zu den beiden anderen hinzugefügt, so dass die Zeiten nur den Unterschied in der Logik zeigen.stmt
auf timeit
Instanzen werden nur einmal ausgeführt Die ursprüngliche Methode, mit der ich das gemacht habe, war die while
Schleife an demselben Label gearbeitet, original_string
Beim zweiten Durchgang gäbe es also nichts mehr zu tun. So wie es jetzt eingerichtet ist, eine Funktion aufzurufen, die zwei verschiedene Bezeichnungen verwendet, ist das kein Problem. Ich habe hinzugefügt assert
Anweisungen an alle Arbeiter, um zu überprüfen, ob wir bei jeder Iteration etwas ändern (für diejenigen, die vielleicht Zweifel haben). Z.B., ändere 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
Für die triviale Zeichenkette scheint eine while-Schleife am schnellsten zu sein, gefolgt von Pythonic string-split/join und regex, das das Schlusslicht bildet.
Für nicht-triviale Zeichenketten scheint es, als gäbe es noch etwas mehr zu bedenken. 32-Bit 2.7? Regex ist die Rettung! 2.7 64-Bit? A while
Schleife ist mit Abstand am besten. 32-Bit 3.2, gehen Sie mit dem "richtigen" join
. 64-bit 3.3, wählen Sie eine while
Schleife. Nochmals.
Letztendlich kann man die Leistung verbessern falls/wo/wann erforderlich aber es ist immer am besten, wenn erinnere dich an das Mantra :
IANAL, YMMV, Caveat Emptor!
Ich muss dem Kommentar von Paul McGuire zustimmen. Für mich,
' '.join(the_string.split())
ist der Verwendung einer Regex bei weitem vorzuziehen.
Meine Messungen (Linux und Python 2.5) zeigen, dass Split-then-Join fast fünfmal schneller ist als "re.sub(...)", und immer noch dreimal schneller, wenn man die Regex einmal vorkompiliert und die Operation mehrfach durchführt. Und es ist auf jeden Fall einfacher zu verstehen -- viel mehr pythonisch.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
31 Stimmen
Woher kommt Ihre Abneigung gegen Listen? Sie sind ein integraler Bestandteil der Sprache, und " ".join(list_of_words) ist eines der wichtigsten Idiome, um eine Liste von Zeichenketten in eine einzige, durch Leerzeichen getrennte Zeichenkette zu verwandeln.
5 Stimmen
@Tom/@Paul: Für einfache Strings wäre (string) join einfach und nett. Aber es wird komplexer, wenn es andere Leerzeichen gibt, die man NICHT stören will... in diesem Fall wären "while" oder Regex-Lösungen am besten. Nachfolgend habe ich eine "korrekte" String-Verknüpfung gepostet, mit zeitlich begrenzten Testergebnissen für drei Möglichkeiten, dies zu tun.