it-swarm.com.de

Einen String in Wörter und Satzzeichen aufteilen

Ich versuche, eine Zeichenfolge in Wörter und Interpunktion aufzuteilen, und die Interpunktion zu der durch die Aufteilung erzeugten Liste hinzuzufügen.

Zum Beispiel:

>>> c = "help, me"
>>> print c.split()
['help,', 'me']

Ich möchte, dass die Liste wirklich so aussieht:

['help', ',', 'me']

Also möchte ich, dass die Zeichenfolge im Leerraum aufgeteilt wird, wobei die Satzzeichen von den Wörtern getrennt werden.

Ich habe versucht, die Zeichenfolge zuerst zu analysieren und dann den Split auszuführen:

>>> for character in c:
...     if character in ".,;!?":
...             outputCharacter = " %s" % character
...     else:
...             outputCharacter = character
...     separatedPunctuation += outputCharacter
>>> print separatedPunctuation
help , me
>>> print separatedPunctuation.split()
['help', ',', 'me']

Dies führt zu dem gewünschten Ergebnis, ist jedoch bei großen Dateien schmerzhaft langsam.

Gibt es eine Möglichkeit, dies effizienter zu machen?

52
David A

Dies ist mehr oder weniger der Weg, dies zu tun:

>>> import re
>>> re.findall(r"[\w']+|[.,!?;]", "Hello, I'm a string!")
['Hello', ',', "I'm", 'a', 'string', '!']

Der Trick besteht darin, nicht darüber nachzudenken, wo die Zeichenfolge aufgeteilt werden soll, sondern was in den Tokens enthalten sein soll.

Vorsichtsmaßnahmen:

  • Der Unterstrich (_) wird als Inner-Word-Zeichen betrachtet. Ersetzen Sie\w, wenn Sie das nicht möchten.
  • Dies funktioniert nicht mit (einfachen) Anführungszeichen in der Zeichenfolge.
  • Setzen Sie alle zusätzlichen Satzzeichen, die Sie verwenden möchten, in die rechte Hälfte des regulären Ausdrucks.
  • Alles, was nicht ausdrücklich erwähnt wurde, wird stumm fallen gelassen.
73
user3850

Hier ist eine Unicode-fähige Version:

re.findall(r"\w+|[^\w\s]", text, re.UNICODE)

Die erste Alternative fängt Sequenzen von Word-Zeichen ein (wie durch Unicode definiert, sodass aus "Lebenslauf" kein ['r', 'sum'] wird); Der zweite fängt einzelne Nicht-Word-Zeichen ab und ignoriert Leerzeichen.

Beachten Sie, dass im Gegensatz zur ersten Antwort das einfache Anführungszeichen als separate Interpunktion behandelt wird (z. B. "I'm" -> ['I', "'", 'm']). Dies scheint in NLP Standard zu sein, daher halte ich es für eine Funktion.

30
LaC

In der Perl-Stil-Syntax für reguläre Ausdrücke stimmt \b mit einer Word-Grenze überein. Dies sollte für einen regexbasierten Split nützlich sein.

edit: Ich wurde von hop informiert, dass "leere Übereinstimmungen" in der Split-Funktion des re-Moduls von Python nicht funktionieren. Ich werde dies hier als Information für alle anderen lassen, die von diesem "Feature" überrascht werden.

5
Svante

Hier ist mein Eintrag.

Ich bezweifle, wie gut dies im Sinne der Effizienz halten wird oder ob es alle Fälle erfasst (beachten Sie das "!!!" in einer Gruppe; dies kann eine gute Sache sein oder nicht).

>>> import re
>>> import string
>>> s = "Helo, my name is Joe! and i live!!! in a button; factory:"
>>> l = [item for item in map(string.strip, re.split("(\W+)", s)) if len(item) > 0]
>>> l
['Helo', ',', 'my', 'name', 'is', 'Joe', '!', 'and', 'i', 'live', '!!!', 'in', 'a', 'button', ';', 'factory', ':']
>>>

Eine naheliegende Optimierung wäre, den Regex vor dem Kompilieren (re.compile) zu kompilieren, wenn Sie dies zeilenweise tun. 

3
Chris Cameron

Hier ist ein kleines Update für Ihre Implementierung. Wenn Sie versuchen, etwas detaillierter zu tun, schlage ich vor, in die NLTK zu schauen, die der Dorforf vorgeschlagen hat.

Dies kann nur etwas schneller sein, da '' .join () anstelle von + = verwendet wird, was bekanntermaßen schneller ist .

import string

d = "Hello, I'm a string!"

result = []
Word = ''

for char in d:
    if char not in string.whitespace:
        if char not in string.ascii_letters + "'":
            if Word:
                    result.append(Word)
            result.append(char)
            Word = ''
        else:
            Word = ''.join([Word,char])

    else:
        if Word:
            result.append(Word)
            Word = ''
print result
['Hello', ',', "I'm", 'a', 'string', '!']
1
monkut

Ich denke, Sie können alle Hilfe, die Sie sich vorstellen können, in der NLTK finden, zumal Sie Python verwenden. Es gibt eine gute ausführliche Diskussion dieses Themas im Tutorial.

0
dkretz

Versuche dies:

string_big = "One of Python's coolest features is the string format operator  This operator is unique to strings"
my_list =[]
x = len(string_big)
poistion_ofspace = 0
while poistion_ofspace < x:
    for i in range(poistion_ofspace,x):
        if string_big[i] == ' ':
            break
        else:
            continue
    print string_big[poistion_ofspace:(i+1)]
    my_list.append(string_big[poistion_ofspace:(i+1)])
    poistion_ofspace = i+1

print my_list
0

Wenn Sie auf Englisch arbeiten (oder in anderen gängigen Sprachen), können Sie NLTK verwenden (dazu gibt es viele andere Tools wie FreeLing ).

import nltk
sentence = "help, me"
nltk.Word_tokenize(sentence)

Ich habe einen Weg gefunden, alle Wörter und \W+-Muster mit \b zu kennzeichnen, was kein Hardcoding erfordert:

>>> import re
>>> sentence = 'Hello, world!'
>>> tokens = [t.strip() for t in re.findall(r'\b.*?\S.*?(?:\b|$)', sentence)]
['Hello', ',', 'world', '!']

Hier ist .*?\S.*? ein Muster, das mit einem beliebigen Objekt übereinstimmt, das kein Leerzeichen ist, und $ wird hinzugefügt, um mit dem letzten Token in einer Zeichenfolge übereinzustimmen, wenn es ein Interpunktionssymbol ist.

Beachten Sie jedoch Folgendes: Dies gruppiert Satzzeichen, die aus mehr als einem Symbol bestehen:

>>> print [t.strip() for t in re.findall(r'\b.*?\S.*?(?:\b|$)', '"Oh no", she said')]
['Oh', 'no', '",', 'she', 'said']

Natürlich können Sie solche Gruppen finden und spalten mit:

>>> for token in [t.strip() for t in re.findall(r'\b.*?\S.*?(?:\b|$)', '"You can", she said')]:
...     print re.findall(r'(?:\w+|\W)', token)

['You']
['can']
['"', ',']
['she']
['said']
0
FrauHahnhen