J'essaie de scinder une chaîne en mots et en ponctuation, en ajoutant la ponctuation à la liste produite par la scission.
Par exemple:
>>> c = "help, me"
>>> print c.split()
['help,', 'me']
Ce que je veux vraiment que la liste ressemble à ceci est:
['help', ',', 'me']
Donc, je veux que la chaîne soit scindée en blanc avec la ponctuation divisée par les mots.
J'ai d'abord essayé d'analyser la chaîne, puis d'exécuter la scission:
>>> for character in c:
... if character in ".,;!?":
... outputCharacter = " %s" % character
... else:
... outputCharacter = character
... separatedPunctuation += outputCharacter
>>> print separatedPunctuation
help , me
>>> print separatedPunctuation.split()
['help', ',', 'me']
Cela produit le résultat que je veux, mais est terriblement lent pour les gros fichiers.
Y a-t-il un moyen de le faire plus efficacement?
C'est plus ou moins la façon de le faire:
>>> import re
>>> re.findall(r"[\w']+|[.,!?;]", "Hello, I'm a string!")
['Hello', ',', "I'm", 'a', 'string', '!']
L'astuce consiste à ne pas chercher à savoir où scinder la chaîne, mais à inclure dans les jetons.
Mises en garde:
Voici une version compatible avec Unicode:
re.findall(r"\w+|[^\w\s]", text, re.UNICODE)
La première alternative saisit des séquences de caractères Word (comme défini par unicode, afin que "résumé" ne se transforme pas en ['r', 'sum']
); la seconde attrape des caractères individuels non-Word, en ignorant les espaces.
Notez que, contrairement à la réponse principale, le guillemet simple est traité comme une ponctuation distincte (par exemple, "Je suis" -> ['I', "'", 'm']
). Cela semble être standard dans la PNL, donc je considère que c'est une fonctionnalité.
Dans la syntaxe d'expression régulière de style Perl, \b
correspond à une limite de Word. Cela devrait être pratique pour faire une scission basée sur la regex.
edit: J'ai été informé par hop que les "correspondances vides" ne fonctionnent pas dans la fonction split du module re de Python. Je laisserai ceci ici comme information pour quiconque se laisserait dérouter par cette "fonctionnalité".
Voici mon entrée.
J'ai des doutes sur l'efficacité de cette opération, ou sur le fait que tous les cas sont résolus (notez le "!!!" regroupé; cela peut être une bonne chose ou non).
>>> 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', ':']
>>>
Une optimisation évidente consisterait à compiler la regex à l’avance (à l’aide de re.compile) si vous envisagez de le faire ligne par ligne.
Voici une mise à jour mineure de votre implémentation. Si vous essayez de faire quelque chose de plus détaillé, je vous suggère d’examiner le NLTK.
Cela pourrait être un peu plus rapide puisque '' .join () est utilisé à la place de + =, qui est plus rapide .
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', '!']
Je pense que vous pouvez trouver toute l'aide que vous pouvez imaginer dans NLTK , surtout que vous utilisez python. Il y a une bonne discussion complète sur cette question dans le tutoriel.
Essaye ça:
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
Je suis arrivé avec un moyen de tokenize tous les mots et les modèles \W+
en utilisant \b
qui n'a pas besoin de codage en dur:
>>> import re
>>> sentence = 'Hello, world!'
>>> tokens = [t.strip() for t in re.findall(r'\b.*?\S.*?(?:\b|$)', sentence)]
['Hello', ',', 'world', '!']
Ici, .*?\S.*?
est un motif correspondant à tout ce qui n’est pas un espace et $
est ajouté pour correspondre au dernier jeton d’une chaîne s’il s’agit d’un symbole de ponctuation.
Notez cependant que ceci va regrouper les signes de ponctuation composés de plusieurs symboles:
>>> print [t.strip() for t in re.findall(r'\b.*?\S.*?(?:\b|$)', '"Oh no", she said')]
['Oh', 'no', '",', 'she', 'said']
Bien sûr, vous pouvez trouver et scinder ces groupes avec:
>>> 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']