Ich denke, was ich tun möchte, ist eine ziemlich häufige Aufgabe, aber ich habe keine Referenz im Web gefunden. Ich habe Text mit Interpunktion 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, daher habe ich alle Wörter mit der Interpunktion, nachdem ich mich mit Leerzeichen getrennt habe. Irgendwelche Ideen?
str.split()
funktioniert auch ohne ArgumenteAntworten:
Ein Fall, in dem reguläre Ausdrücke gerechtfertigt sind:
quelle
re
, einfach nichtfindall
. Die Antwort untenre.split()
ist überlegen.don't
ein einzelnes Wort behandelt wird, anstatt indon
und aufgeteilt zu werdent
.re.split ()
quelle
\w
,\W
,\s
und\S
. Wer dachte, dass die Großschreibung einer Flagge ihre Bedeutung umkehren sollte, muss durch den Kopf geschossen werden.shift
Schlüssel zu verwenden, um das Gegenteil von etwas zu tun.ctrl+z
rückgängig machen vs.ctrl+shift+z
für wiederholen. Alsoshift w
oderW
wäre das Gegenteil vonw
.Eine andere schnelle Möglichkeit, dies ohne regulären Ausdruck zu tun, besteht darin, zuerst die Zeichen wie folgt zu ersetzen:
quelle
So viele Antworten, aber ich kann keine Lösung finden, die effizient das tut, was der Titel der Fragen buchstäblich verlangt (Aufteilung auf mehrere mögliche Trennzeichen - stattdessen werden viele Antworten auf alles aufgeteilt, was kein Wort ist, das anders ist). Hier ist eine Antwort auf die Frage im Titel, die sich auf Pythons Standard- und effizientes
re
Modul stützt :wo:
[…]
entspricht einem der darin aufgeführten Trennzeichen,\-
im regulären Ausdruck soll hier die spezielle Interpretation-
als Zeichenbereichsindikator (wie inA-Z
) verhindern,+
überspringt ein oder mehrere Trennzeichen (es könnte dank des weggelassen werdenfilter()
, aber dies würde unnötigerweise leere Zeichenfolgen zwischen übereinstimmenden Trennzeichen erzeugen) undfilter(None, …)
Entfernt die leeren Zeichenfolgen, die möglicherweise durch führende und nachfolgende Trennzeichen erstellt wurden (da leere Zeichenfolgen einen falschen booleschen Wert haben).Dies
re.split()
genau "teilt sich 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 gefunden wurden (siehe den ersten Kommentar zur Antwort von ghostdog74 ).
Das
re
Modul ist viel effizienter (in Geschwindigkeit und Präzision) als Python-Schleifen und Tests "von Hand"!quelle
Ein anderer Weg, ohne Regex
quelle
"Hey, you - what are you doing here María!?"
. Die akzeptierte Lösung funktioniert nicht mit dem vorherigen Beispiel.''.join([o if not o in string.punctuation else ' ' for o in s]).split()
o for o in s if (o in not string.punctuation or o == "'")
, aber dann wird es für einen Einzeiler zu kompliziert, wenn wir auch den Patch von cedbeu hinzufügen."First Name,Last Name,Street Address,City,State,Zip Code"
und wir nur durch ein Komma teilen möchten,
. Gewünschte Ausgabe wäre:['First Name', 'Last Name', 'Street Address', 'City', 'State', 'Zip Code']
Was wir stattdessen bekommen:['First', 'Name', 'Last', 'Name', 'Street', 'Address', 'City', 'State', 'Zip', 'Code']
re
Modul Standard ist und sowohl Lesbarkeit als auch Geschwindigkeit bietet, verstehe ich nicht, warum es vermieden werden sollte.Pro-Tipp: Verwenden Sie
string.translate
für die schnellsten String-Operationen, die Python hat.Einige Beweise ...
Erstens der langsame Weg (sorry pprzemek):
Als nächstes verwenden wir
re.findall()
(wie in der vorgeschlagenen Antwort angegeben). Viel schneller:Schließlich verwenden wir
translate
:Erläuterung:
string.translate
ist in C implementiert und erzeugt im Gegensatz zu vielen String-Manipulationsfunktionen in Pythonstring.translate
keinen neuen String. Es ist also so schnell wie möglich, um Zeichenfolgen zu ersetzen.Es ist jedoch etwas umständlich, da es eine Übersetzungstabelle benötigt, um diese Magie auszuführen. Mit der
maketrans()
Convenience-Funktion können Sie eine Übersetzungstabelle erstellen. Ziel ist es, alle unerwünschten Zeichen in Leerzeichen zu übersetzen. Ein Eins-zu-Eins-Ersatz. Auch hier werden keine neuen Daten erzeugt. Das geht also schnell !Als nächstes verwenden wir gute alte
split()
.split()
Standardmäßig werden alle Leerzeichen verarbeitet und für die Aufteilung gruppiert. Das Ergebnis ist die Liste der gewünschten Wörter. Und dieser Ansatz ist fast 4x schneller alsre.findall()
!quelle
patt = re.compile(ur'\w+', re.UNICODE); patt.findall(S)
schneller als die Übersetzung, da Sie die Zeichenfolge vor dem Anwenden der Transformation codieren und jedes Element in der Liste nach dem Teilen dekodieren müssen, um zum Unicode zurückzukehren.s.translate(''.join([(chr(i) if chr(i) not in seps else seps[0]) for i in range(256)])).split(seps[0])
Ich hatte ein ähnliches Dilemma und wollte das 're'-Modul nicht verwenden.
quelle
re
Modul verwenden, das sowohl viel schneller als auch klarer ist (nicht, dass reguläre Ausdrücke besonders klar sind, sondern weil es viel kürzer und direkter ist)?Erstens möchte ich anderen zustimmen, dass die Regex- oder
str.translate(...)
basierten Lösungen am leistungsfähigsten sind. Für meinen Anwendungsfall war die Leistung dieser Funktion nicht signifikant, daher wollte ich Ideen hinzufügen, die ich mit diesen Kriterien berücksichtigte.Mein Hauptziel war es, Ideen aus einigen der anderen Antworten in eine Lösung zu verallgemeinern, die für Zeichenfolgen funktionieren kann, die mehr als nur Regex-Wörter enthalten (dh die explizite Teilmenge von Interpunktionszeichen gegenüber Whitelist-Wortzeichen auf die schwarze Liste setzen).
Beachten Sie, dass bei jedem Ansatz auch die Verwendung
string.punctuation
einer manuell definierten Liste in Betracht gezogen werden kann .Option 1 - re
Ich war überrascht zu sehen, dass bisher keine Antwort re.sub (...) verwendet . Ich finde es eine einfache und natürliche Herangehensweise an dieses Problem.
In dieser Lösung habe ich den Aufruf nach
re.sub(...)
innen verschachteltre.split(...)
- aber wenn die Leistung kritisch ist, kann das Kompilieren des regulären Ausdrucks von außen von Vorteil sein - für meinen Anwendungsfall war der Unterschied nicht signifikant, daher bevorzuge ich Einfachheit und Lesbarkeit.Option 2 - str.replace
Dies sind noch ein paar Zeilen, aber es hat den Vorteil, dass es erweiterbar ist, ohne prüfen zu müssen, ob Sie einem bestimmten Zeichen in Regex entkommen müssen.
Es wäre schön gewesen, die str.replace stattdessen der Zeichenfolge zuordnen zu können, aber ich glaube nicht, dass dies mit unveränderlichen Zeichenfolgen möglich ist, und während die Zuordnung zu einer Liste von Zeichen funktionieren würde, würde jeder Ersatz für jedes Zeichen ausgeführt klingt übertrieben. (Bearbeiten: Ein Funktionsbeispiel finden Sie in der nächsten Option.)
Option 3 - functools.reduce
(In Python 2
reduce
ist es im globalen Namespace verfügbar, ohne es aus functools zu importieren.)quelle
str.translate
- sie ist nicht Unicode-fähig, aber höchstwahrscheinlich schneller als andere Methoden und kann daher in einigen Fällen gut sein:replacements=',-!?'; import string; my_str = my_str.translate(string.maketrans(replacements, ' ' * len(replacements)))
Auch hier ist es obligatorisch, Ersetzungen als Zeichenfolge zu haben, nicht als Tupel oder Liste.Dann wird dies ein Drei-Liner:
Erläuterung
Dies ist, was in Haskell als Listenmonade bekannt ist. Die Idee hinter der Monade ist, dass Sie einmal "in der Monade" "in der Monade bleiben", bis Sie etwas herausholt. Angenommen, Sie ordnen die Python-
range(n) -> [1,2,...,n]
Funktion in Haskell einer Liste zu. Wenn das Ergebnis eine Liste ist, wird es direkt an die Liste angehängt, sodass Sie so etwas wie erhaltenmap(range, [3,4,1]) -> [0,1,2,0,1,2,3,0]
. Dies wird als Map-Append (oder Mappend oder so ähnlich) bezeichnet. Die Idee hier ist, dass Sie diese Operation haben, die Sie anwenden (auf ein Token aufteilen), und wann immer Sie dies tun, fügen Sie das Ergebnis in die Liste ein.Sie können dies in eine Funktion abstrahieren und haben
tokens=string.punctuation
standardmäßig.Vorteile dieses Ansatzes:
quelle
map_then_append
verwendet werden kann, um ein Problem zu einem 2-Zeilen- Problem zu machen, sowie viele andere Probleme, die viel einfacher zu schreiben sind. Die meisten anderen Lösungen verwenden dasre
Modul für reguläre Ausdrücke , bei dem es sich nicht um Python handelt. Aber ich war unzufrieden damit, wie ich meine Antwort unelegant und aufgebläht erscheinen lasse, wenn sie wirklich prägnant ist ... Ich werde sie bearbeiten ...fragments
Ergebnis ist nur eine Liste der Zeichen in der Zeichenfolge (einschließlich der Token).fragments = ['the,string']
,fragments = 'the,string'
oderfragments = list('the,string')
keiner von ihnen den richtigen Output produzieren.Versuche dies:
Dies wird gedruckt
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
quelle
Verwenden Sie zweimal ersetzen:
Ergebnisse in:
quelle
Ich mag re , aber hier ist meine Lösung ohne:
sep .__ enthält__ ist eine Methode, die vom Operator 'in' verwendet wird. Im Grunde ist es das gleiche wie
ist aber hier bequemer.
groupby bekommt unseren String und unsere Funktion. Mit dieser Funktion wird die Zeichenfolge in Gruppen aufgeteilt: Wenn sich ein Funktionswert ändert, wird eine neue Gruppe generiert. Also, sep .__ enthält__ ist genau das, was wir brauchen.
groupby gibt eine Folge von Paaren zurück, wobei pair [0] ein Ergebnis unserer Funktion ist und pair [1] eine Gruppe ist. Mit 'if not k' filtern wir Gruppen mit Trennzeichen heraus (da ein Ergebnis von sep .__ enthält__ auf Trennzeichen True ist). Nun, das ist alles - jetzt haben wir eine Folge von Gruppen, in denen jedes ein Wort ist (Gruppe ist eigentlich iterierbar, also verwenden wir join , um es in einen String umzuwandeln).
Diese Lösung ist recht allgemein gehalten, da sie eine Funktion zum Trennen von Zeichenfolgen verwendet (Sie können nach jeder gewünschten Bedingung aufteilen). Außerdem werden keine Zwischenzeichenfolgen / -listen erstellt (Sie können Join entfernen und der Ausdruck wird faul, da jede Gruppe ein Iterator ist).
quelle
Anstatt eine re-Modulfunktion re.split zu verwenden, können Sie mit der Pandas-Methode series.str.split dasselbe Ergebnis erzielen.
Erstellen Sie zuerst eine Serie mit der obigen Zeichenfolge und wenden Sie dann die Methode auf die Serie an.
thestring = pd.Series("Hey, you - what are you doing here!?") thestring.str.split(pat = ',|-')
Der Parameter pat nimmt die Trennzeichen und gibt die geteilte Zeichenfolge als Array zurück. Hier werden die beiden Trennzeichen mit einem | übergeben (oder Betreiber). Die Ausgabe ist wie folgt:
[Hey, you , what are you doing here!?]
quelle
Ich mache mich wieder mit Python vertraut und brauchte das Gleiche. Die Lösung ist vielleicht besser, aber ich habe mir Folgendes ausgedacht:
quelle
Mit Maketrans und Übersetzern können Sie dies einfach und ordentlich tun
quelle
In Python 3 können Sie die Methode von PY4E - Python for Everybody verwenden .
your_string.translate(your_string.maketrans(fromstr, tostr, deletestr))
Sie können die "Interpunktion" sehen:
Für Ihr Beispiel:
Weitere Informationen finden Sie unter:
quelle
Eine andere Möglichkeit, dies zu erreichen, ist die Verwendung des Natural Language Tool Kit ( nltk ).
Dies druckt:
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Der größte Nachteil dieser Methode ist, dass Sie das nltk-Paket installieren müssen .
Die Vorteile sind, dass Sie mit dem Rest des nltk-Pakets eine Menge Spaß machen können, sobald Sie Ihre Token erhalten haben.
quelle
Erstens glaube ich nicht, dass Sie beabsichtigen, Interpunktion als Trennzeichen in den Teilungsfunktionen zu verwenden. Ihre Beschreibung legt nahe, dass Sie einfach Interpunktion aus den resultierenden Zeichenfolgen entfernen möchten.
Ich stoße ziemlich häufig darauf, und meine übliche Lösung erfordert keine erneute Lösung.
Einzeilige Lambda-Funktion mit Listenverständnis:
(erfordert
import string
):Funktion (traditionell)
Als traditionelle Funktion sind dies immer noch nur zwei Zeilen mit einem Listenverständnis (zusätzlich zu
import string
):Es wird natürlich auch Kontraktionen und getrennte Wörter intakt lassen. Sie können
text.replace("-", " ")
Bindestriche vor dem Teilen immer in Leerzeichen umwandeln.Allgemeine Funktion ohne Lambda oder Listenverständnis
Für eine allgemeinere Lösung (bei der Sie die zu eliminierenden Zeichen angeben können) und ohne Listenverständnis erhalten Sie:
Natürlich können Sie die Lambda-Funktion auch jederzeit auf eine bestimmte Zeichenfolge verallgemeinern.
quelle
Verwenden Sie zunächst immer re.compile (), bevor Sie eine RegEx-Operation in einer Schleife ausführen, da diese schneller als die normale Operation arbeitet.
Kompilieren Sie für Ihr Problem zuerst das Muster und führen Sie dann eine Aktion aus.
quelle
Hier ist die Antwort mit einer Erklärung.
oder in einer Zeile können wir Folgendes tun:
aktualisierte Antwort
quelle
Erstellen Sie eine Funktion, die als Eingabe zwei Zeichenfolgen (die zu teilende Quellzeichenfolge und die Teilungszeichenfolge mit Trennzeichen) verwendet und eine Liste mit Teilwörtern ausgibt:
quelle
Ich mag die Lösung von pprzemek, weil sie nicht davon ausgeht, dass die Trennzeichen einzelne Zeichen sind, und nicht versucht, einen regulären Ausdruck zu nutzen (was nicht gut funktionieren würde, wenn die Anzahl der Trennzeichen lang verrückt werden müsste).
Hier ist aus Gründen der Übersichtlichkeit eine besser lesbare Version der obigen Lösung:
quelle
habe das gleiche Problem wie @ooboo und finde dieses Thema @ ghostdog74 hat mich inspiriert, vielleicht findet jemand meine Lösung nützlich
Geben Sie etwas an der Stelle ein und teilen Sie es mit demselben Zeichen, wenn Sie nicht an Stellen teilen möchten.
quelle
Hier ist meine Entscheidung für eine Trennung mit mehreren Begrenzern:
quelle
Ich denke, Folgendes ist die beste Antwort, um Ihren Anforderungen gerecht zu werden:
\W+
Vielleicht für diesen Fall geeignet, aber möglicherweise nicht für andere Fälle.quelle
\w
und\W
Lösungen sind keine Antwort auf (den Titel) der Frage. Beachten Sie, dass in Ihrer Antwort entfernt werden|
sollte (Sie denken anexpr0|expr1
statt[char0 char1…]
). Darüber hinaus istcompile()
der reguläre Ausdruck nicht erforderlich .Hier ist meine Meinung dazu ....
quelle
Mir gefällt der
replace()
Weg am besten. Das folgende Verfahren ändert alle in einer Zeichenfolge definiertensplitlist
Trennzeichen in das erste Trennzeichen insplitlist
und teilt dann den Text in dieses eine Trennzeichen auf. Es wird auch berücksichtigt, obsplitlist
es sich um eine leere Zeichenfolge handelt. Es wird eine Liste von Wörtern ohne leere Zeichenfolgen zurückgegeben.quelle
Hier ist die Verwendung:
quelle
Wenn Sie eine umkehrbare Operation wünschen (Trennzeichen beibehalten), können Sie diese Funktion verwenden:
quelle
Ich musste dies kürzlich tun, wollte aber eine Funktion, die etwas mit der Standardbibliotheksfunktion übereinstimmt.
str.split
Diese Funktion verhält sich genauso wie die Standardbibliothek, wenn sie mit 0 oder 1 Argumenten aufgerufen wird.HINWEIS : Diese Funktion ist nur nützlich, wenn Ihre Trennzeichen aus einem einzelnen Zeichen bestehen (wie in meinem Anwendungsfall).
quelle