Teilen Sie Zeichenfolgen mit mehreren Wortbegrenzungszeichen in Wörter auf

Lesezeit: 10 Minuten

Benutzer-Avatar
ooboo

Ich denke, was ich tun möchte, ist eine ziemlich häufige Aufgabe, aber ich habe keine Referenz im Internet gefunden. Ich habe Text mit Satzzeichen und möchte eine Liste der Wörter.

"Hey, you - what are you doing here!?"

sollte sein

['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

Aber Pythons str.split() funktioniert nur mit einem Argument, also habe ich alle Wörter mit Satzzeichen, nachdem ich mit Leerzeichen geteilt habe. Irgendwelche Ideen?

  • docs.python.org/library/re.html

    – mtasic85

    29. Juni 2009 um 18:03 Uhr

  • Pythons str.split() funktioniert auch ganz ohne Argumente

    – Iwan Winogradow

    8. Mai 2018 um 9:04 Uhr

Benutzer-Avatar
Richie Hindle

Ein Fall, in dem reguläre Ausdrücke gerechtfertigt sind:

import re
DATA = "Hey, you - what are you doing here!?"
print re.findall(r"[\w']+", DATA)
# Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

  • Vielen Dank. Trotzdem interessiert – wie kann ich den in diesem Modul verwendeten Algorithmus implementieren? Und warum erscheint es nicht im Stringmodul?

    – ooboo

    29. Juni 2009 um 18:06 Uhr

  • Reguläre Ausdrücke können zunächst entmutigend sein, sind aber sehr mächtig. Der reguläre Ausdruck ‘\w+’ bedeutet “ein Wortzeichen (az usw.), das einmal oder mehrmals wiederholt wird”. Hier finden Sie ein HOWTO zu regulären Ausdrücken in Python: amk.ca/python/howto/regex

    – Richie Hindle

    4. Juli 2009 um 19:44 Uhr

  • Dies ist nicht die Antwort auf die Frage. Dies ist eine Antwort auf eine andere Frage, die zufällig für diese spezielle Situation funktioniert. Es ist, als würde jemand fragen: „Wie biege ich links ab“ und die am häufigsten gewählte Antwort lautete „Nehmen Sie die nächsten drei Rechtskurven“. Es funktioniert für bestimmte Kreuzungen, aber es gibt nicht die benötigte Antwort. Ironischerweise die Antwort ist in reeinfach nicht findall. Die Antwort unten geben re.split() ist überlegen.

    – Jesse Dillon

    9. September 2013 um 18:47 Uhr

  • @JesseDhillon “alle Teilzeichenfolgen nehmen, die aus einer Folge von Wortzeichen bestehen” und “auf alle Teilzeichenfolgen aufteilen, die aus einer Folge von Nichtwortzeichen bestehen” sind buchstäblich nur unterschiedliche Möglichkeiten, dieselbe Operation auszudrücken. Ich bin mir nicht sicher, warum Sie eine der Antworten überlegen nennen würden.

    – Mark Amery

    13. Juli 2015 um 17:51 Uhr

  • @TMWP: Der Apostoph bedeutet, dass ein Wort wie don't wird als ein einziges Wort behandelt und nicht aufgeteilt don und t.

    – Richie Hindle

    21. März 2017 um 14:48 Uhr

  • Schnell und schmutzig, aber perfekt für meinen Fall (meine Trennzeichen waren ein kleines, bekanntes Set)

    – Andy Bäcker

    1. September 2012 um 9:34 Uhr

  • Perfekt für den Fall, dass Sie keinen Zugriff auf die RE-Bibliothek haben, wie z. B. bestimmte kleine Mikrocontroller. 🙂

    – tudor -Monica wieder einsetzen-

    1. Mai 2014 um 3:40 Uhr

  • Ich denke, das ist auch expliziter als RE, also ist es irgendwie Noob-freundlich. Manchmal braucht man keine allgemeine Lösung für alles

    – Adam Hughes

    24. Januar 2015 um 5:47 Uhr

  • Genial. Ich hatte eine .split() in einer Situation mit mehreren Eingaben und musste abfangen, wenn der Benutzer, ich, die Eingaben mit einem Leerzeichen und nicht mit einem Komma trennte. Ich wollte schon aufgeben und mit re umwandeln, aber Ihre .replace()-Lösung traf den Nagel auf den Kopf. Vielen Dank.

    – JayJay123

    6. Juli 2015 um 2:22 Uhr

  • Viel klarer als eine Regex. Außerdem habe ich keine Lust, ein ganzes Modul zu importieren, nur um eine einzelne, scheinbar einfache Operation auszuführen.

    – Przemek D

    13. Juni 2018 um 12:33 Uhr

Benutzer-Avatar
Eric O Lebigot

So viele Antworten, aber ich kann keine Lösung finden, die das effizient macht Titel der Fragen buchstäblich verlangt (Aufteilung auf mehrere mögliche Trennzeichen – stattdessen werden viele Antworten auf alles aufgeteilt, was kein Wort ist, was anders ist). Hier ist also eine Antwort auf die Frage im Titel, die sich auf Pythons Standard und Effizienz stützt re Modul:

>>> import re  # Will be splitting on: , <space> - ! ? :
>>> filter(None, re.split("[, \-!?:]+", "Hey, you - what are you doing here!?"))
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

wo:

  • das […] Streichhölzer eines der darin aufgeführten Trennzeichen,
  • das \- im regulären Ausdruck soll hier die spezielle Interpretation von verhindern - als Zeichenbereichsanzeige (wie in A-Z),
  • das + überspringt einen oder mehr Trennzeichen (kann dank der filter()aber dies würde unnötigerweise leere Zeichenfolgen zwischen übereinstimmenden Einzelzeichen-Trennzeichen erzeugen), und
  • filter(None, …) entfernt die möglicherweise durch führende und nachfolgende Trennzeichen erzeugten leeren Zeichenfolgen (da leere Zeichenfolgen einen falschen booleschen Wert haben).

Dies re.split() genau “Splits mit mehreren Trennzeichen”, wie im Fragentitel gefordert.

Diese Lösung ist außerdem immun gegen die Probleme mit Nicht-ASCII-Zeichen in Wörtern, die in einigen anderen Lösungen zu finden sind (siehe den ersten Kommentar zur Antwort von ghostdog74).

Das re -Modul ist viel effizienter (in Bezug auf Geschwindigkeit und Prägnanz) als Python-Schleifen und -Tests “von Hand” durchzuführen!

  • “Ich kann keine Lösung finden, die effizient das tut, was der Titel der Fragen wörtlich verlangt” – die zweite Antwort, die vor 5 Jahren gepostet wurde: stackoverflow.com/a/1059601/2642204.

    – BartoszKP

    2. Dezember 2014 um 14:00 Uhr


  • Diese Antwort wird nicht an Trennzeichen geteilt (aus einer Reihe von mehreren Trennzeichen): Sie wird stattdessen an allem geteilt, was nicht alphanumerisch ist. Trotzdem stimme ich zu, dass die Absicht des ursprünglichen Posters wahrscheinlich darin besteht, nur die Wörter beizubehalten, anstatt einige Satzzeichen zu entfernen.

    – Eric O. Lebigot

    2. Dezember 2014 um 14:31 Uhr

  • EOL: Ich denke, diese Antwort teilt sich in mehrere Trennzeichen auf. Wenn Sie der Zeichenfolge nicht alphanumerische Zeichen hinzufügen, die nicht angegeben sind, z. B. Unterstriche, werden sie nicht wie erwartet geteilt.

    – GravityWell

    7. Dezember 2014 um 20:33 Uhr

  • @EOL: Ich habe gerade festgestellt, dass ich von Ihrem Kommentar “Diese Antwort wird nicht geteilt …” verwirrt war. Ich dachte, “dies” bezog sich auf Ihre re.split-Antwort, aber mir ist jetzt klar, dass Sie Gimels Antwort gemeint haben. Ich denke, DIESE Antwort (die Antwort, die ich kommentiere) ist die beste Antwort 🙂

    – GravityWell

    8. Dezember 2014 um 12:38 Uhr


  • Die Ironie hier ist der Grund, warum diese Antwort nicht die meisten Stimmen erhält … es gibt technisch korrekte Antworten und dann gibt es das, wonach der ursprüngliche Anforderer sucht (was sie meinen und nicht was sie sagen). Dies ist eine großartige Antwort und ich habe sie kopiert, wenn ich sie brauche. Und doch löst die am besten bewertete Antwort für mich ein Problem, das dem sehr ähnlich ist, woran der Poster gearbeitet hat, schnell, sauber und mit minimalem Code. Wenn eine einzige Antwort beide Lösungen gepostet hätte, hätte ich dafür 4 gestimmt. Welche 1 besser ist, hängt davon ab, was Sie tatsächlich versuchen zu tun (nicht die “How-To”-Quest, die gefragt wird). 🙂

    – TMWP

    21. März 2017 um 17:45 Uhr

Benutzer-Avatar
Terry A

Ein anderer Weg, ohne Regex

import string
punc = string.punctuation
thestring = "Hey, you - what are you doing here!?"
s = list(thestring)
''.join([o for o in s if not o in punc]).split()

  • “Ich kann keine Lösung finden, die effizient das tut, was der Titel der Fragen wörtlich verlangt” – die zweite Antwort, die vor 5 Jahren gepostet wurde: stackoverflow.com/a/1059601/2642204.

    – BartoszKP

    2. Dezember 2014 um 14:00 Uhr


  • Diese Antwort wird nicht an Trennzeichen geteilt (aus einer Reihe von mehreren Trennzeichen): Sie wird stattdessen an allem geteilt, was nicht alphanumerisch ist. Trotzdem stimme ich zu, dass die Absicht des ursprünglichen Posters wahrscheinlich darin besteht, nur die Wörter beizubehalten, anstatt einige Satzzeichen zu entfernen.

    – Eric O. Lebigot

    2. Dezember 2014 um 14:31 Uhr

  • EOL: Ich denke, diese Antwort teilt sich in mehrere Trennzeichen auf. Wenn Sie der Zeichenfolge nicht alphanumerische Zeichen hinzufügen, die nicht angegeben sind, z. B. Unterstriche, werden sie nicht wie erwartet geteilt.

    – GravityWell

    7. Dezember 2014 um 20:33 Uhr

  • @EOL: Ich habe gerade festgestellt, dass ich von Ihrem Kommentar “Diese Antwort wird nicht geteilt …” verwirrt war. Ich dachte, “dies” bezog sich auf Ihre re.split-Antwort, aber mir ist jetzt klar, dass Sie Gimels Antwort gemeint haben. Ich denke, DIESE Antwort (die Antwort, die ich kommentiere) ist die beste Antwort 🙂

    – GravityWell

    8. Dezember 2014 um 12:38 Uhr


  • Die Ironie hier ist der Grund, warum diese Antwort nicht die meisten Stimmen erhält … es gibt technisch korrekte Antworten und dann gibt es das, wonach der ursprüngliche Anforderer sucht (was sie meinen und nicht was sie sagen). Dies ist eine großartige Antwort und ich habe sie kopiert, wenn ich sie brauche. Und doch löst die am besten bewertete Antwort für mich ein Problem, das dem sehr ähnlich ist, woran der Poster gearbeitet hat, schnell, sauber und mit minimalem Code. Wenn eine einzige Antwort beide Lösungen gepostet hätte, hätte ich dafür 4 gestimmt. Welche 1 besser ist, hängt davon ab, was Sie tatsächlich versuchen zu tun (nicht die “How-To”-Quest, die gefragt wird). 🙂

    – TMWP

    21. März 2017 um 17:45 Uhr

Benutzer-Avatar
Jewgeni Sergejew

Pro-Tipp: Verwenden string.translate für die schnellsten Zeichenfolgenoperationen, die Python hat.

Einige Beweise …

Zuerst der langsame Weg (sorry pprzemek):

>>> import timeit
>>> S = 'Hey, you - what are you doing here!?'
>>> def my_split(s, seps):
...     res = [s]
...     for sep in seps:
...         s, res = res, []
...         for seq in s:
...             res += seq.split(sep)
...     return res
... 
>>> timeit.Timer('my_split(S, punctuation)', 'from __main__ import S,my_split; from string import punctuation').timeit()
54.65477919578552

Als nächstes verwenden wir re.findall() (wie in der vorgeschlagenen Antwort angegeben). Viel schneller:

>>> timeit.Timer('findall(r"\w+", S)', 'from __main__ import S; from re import findall').timeit()
4.194725036621094

Schließlich verwenden wir translate:

>>> from string import translate,maketrans,punctuation 
>>> T = maketrans(punctuation, ' '*len(punctuation))
>>> timeit.Timer('translate(S, T).split()', 'from __main__ import S,T,translate').timeit()
1.2835021018981934

Erläuterung:

string.translate ist in C implementiert und im Gegensatz zu vielen String-Manipulationsfunktionen in Python, string.translate nicht eine neue Saite erzeugen. Es ist also ungefähr so ​​​​schnell, wie Sie für die Zeichenfolgensubstitution bekommen können.

Es ist jedoch etwas umständlich, da es eine Übersetzungstabelle benötigt, um diese Magie auszuführen. Sie können eine Übersetzungstabelle mit erstellen maketrans() Komfortfunktion. Das Ziel hier ist, alle unerwünschten Zeichen in Leerzeichen zu übersetzen. Ein Eins-zu-Eins-Ersatz. Auch hier werden keine neuen Daten erzeugt. Das ist also schnell!

Als nächstes verwenden wir das gute alte split(). split() arbeitet standardmäßig mit allen Leerzeichen und gruppiert sie für die Teilung. Das Ergebnis ist die Liste der gewünschten Wörter. Und dieser Ansatz ist fast 4x schneller als re.findall()!

  • Ich habe hier einen Test gemacht, und wenn Sie Unicode verwenden müssen, verwenden Sie patt = re.compile(ur'\w+', re.UNICODE); patt.findall(S) ist schneller als translate, da Sie die Zeichenfolge codieren müssen, bevor Sie die Transformation anwenden, und jedes Element in der Liste nach der Teilung decodieren müssen, um zu Unicode zurückzukehren.

    – Rafael S. Calsaverini

    15. Januar 2013 um 11:31 Uhr

  • Sie können die Übersetzungsimplementierung einzeilig machen und sicherstellen, dass S nicht zu den Splittern gehört, mit: s.translate(''.join([(chr(i) if chr(i) not in seps else seps[0]) for i in range(256)])).split(seps[0])

    – Kochfelder

    1. April 2014 um 22:56 Uhr


  • Keine genommen. Du vergleichst Äpfel und Birnen. 😉 Meine Lösung in Python 3 funktioniert immer noch ;P und unterstützt Trennzeichen mit mehreren Zeichen. 🙂 Versuchen Sie das auf einfache Weise, ohne einen neuen String zuzuweisen. 🙂 aber wahr, meins beschränkt sich auf das Analysieren von Befehlszeilenparametern und nicht zum Beispiel auf ein Buch.

    – pprzemek

    27. Oktober 2017 um 10:17 Uhr

  • Sie sagen “erzeugt keine neue Zeichenfolge”, was bedeutet, dass es an der angegebenen Zeichenfolge funktioniert? Ich habe es jetzt mit Python 2.7 getestet und es ändert die ursprüngliche Zeichenfolge nicht und gibt eine neue zurück.

    – Prokop Hapala

    15. September 2019 um 10:27 Uhr

  • string.translate und string.maketrans sind in Python 3 nicht verfügbar, sondern nur in Python 2.

    – Futal

    28. Oktober 2021 um 11:03 Uhr

1137390cookie-checkTeilen Sie Zeichenfolgen mit mehreren Wortbegrenzungszeichen in Wörter auf

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy