1
votes

Nettoyage du texte avec python et re

J'ai besoin de nettoyer du texte comme le code ci-dessous dit:

In [10] :clean_questions= [] 
   ...: for question in questions: 
   ...: clean_questions.append(clean_text(question))
Traceback (most recent call last):

  File "<ipython-input-6-d1c7ac95a43f>", line 3, in <module>
    clean_questions.append(clean_text(question))

  File "<ipython-input-5-8f5da8f003ac>", line 16, in clean_text
    text = re.sub(r"[-()\"#/@;:<>{}-=~|.?,]","",text)

  File "C:\Users\hp\Anaconda3\lib\re.py", line 192, in sub
    return _compile(pattern, flags).sub(repl, string, count)

  File "C:\Users\hp\Anaconda3\lib\re.py", line 286, in _compile
   p = sre_compile.compile(pattern, flags)

  File "C:\Users\hp\Anaconda3\lib\sre_compile.py", line 764, in compile
    p = sre_parse.parse(p, flags)

  File "C:\Users\hp\Anaconda3\lib\sre_parse.py", line 930, in parse
    p = _parse_sub(source, pattern, flags & SRE_FLAG_VERBOSE, 0)

  File "C:\Users\hp\Anaconda3\lib\sre_parse.py", line 426, in _parse_sub
    not nested and not items))

  File "C:\Users\hp\Anaconda3\lib\sre_parse.py", line 580, in _parse
    raise source.error(msg, len(this) + 1 + len(that))

error: bad character range }-=

et ce code doit me donner la liste des questions propre mais j'ai obtenu le questions vide. J'ai rouvert le spyder et la liste est devenue pleine mais sans être nettoyée, puis je l'ai rouverte et je l'ai vide. l'erreur de console dit:

import re
def clean_text(text):
    text = text.lower()
    #foction de replacement
    text = re.sub(r"i'm","i am",text)
    text = re.sub(r"she's","she is",text)
    text = re.sub(r"can't","cannot",text)
    text = re.sub(r"[-()\"#/@;:<>{}-=~|.?,]","",text)
    return text

clean_questions= []
for question in questions: 
    clean_questions.append(clean_text(question))

J'utilise Python 3.6, en particulier la version Anaconda Anaconda3-2018.12-Windows-x86_64.


5 commentaires

Échappez à \ {\} dans le dernier motif. Mais vous avez probablement besoin d'une classe de caractères à la place: "[- () \" # / @ ;: <> {} = ~ |.?,] + ".


@AndrasDeak: Le retraçage montre qu'ils utilisaient une classe de caractères. Le vrai problème est donc une classe mauvaise , pas l’absence d’une classe.


@dasertnaut Je suis aux premiers pas de la création d'un chatbot avec DNLP


@AndrasDeak j'ai supprimé toute la phrase mais rien n'a changé


Les réponses existantes devraient expliquer suffisamment bien quel est le problème; tu ne comprends toujours pas Le problème de premier niveau est que } - = signifie "de } à = dans le tableau ASCII" à l'intérieur d'un groupe de caractères (crochets) .


3 Réponses :


0
votes

Vous devez correctement échapper les caractères spéciaux et les mettre entre crochets

[^a-zA-Z0-9]

Une expression régulière plus générique est pour les caractères spéciaux (c'est-à-dire pas une lettre ou un chiffre) est

re.sub(r'[-\(\)\"#\/@;:<>\{\}\-=~|\.\?]', '', some_text)


2 commentaires

Remarque: Bien que non nuisibles, la plupart des caractères spéciaux perdent leur signification particulière à l'intérieur des jeux de caractères, vous n'avez donc pas besoin d'autant d'échappements que vous avez utilisés (vous avez également supprimé de manière inexplicable certains caractères, tels que , , de la ensemble). Je pense que r "[- () \" # / @ ;: <> {} = ~ |.?,] " devrait fonctionner correctement (en supprimant uniquement le deuxième - , car il était déjà inclus au début sur la classe dans une position où l'échappement n'était pas nécessaire).


Citation de soutien de la documentation : "Les caractères spéciaux perdent leur signification particulière à l'intérieur d'ensembles. Par exemple, [(+ *)] correspondra à l'un des caractères littéraux '(' , '+' , '*' , ou ')' . " Ainsi, les parenthèses d'échappement, les accolades, les points, les barres obliques et les points d'interrogation sont tous inutiles; à main levée uniquement \ (n'importe où), - (au milieu d'une classe), ^ (au début d'une classe), ] ( pas au début d'une classe), et quelques éléments aléatoires dans le lien qui concernent la prise en charge future des ensembles imbriqués ( [, - , && , ~~ , || ) doivent être échappés.



5
votes

Votre classe de caractères (comme indiqué dans le traçage) n'est pas valide; } vient après = en valeur ordinale (} est 125, = est 61), et le - entre eux signifie qu'il essaie de faire correspondre n'importe quel caractère de l'ordinal de } à celui de = et entre les deux. Puisque les plages de caractères doivent aller de l'ordinal bas à l'ordinal élevé, 125-> 61 n'a aucun sens, donc l'erreur.

D'une certaine manière, vous avez eu de la chance; si les caractères autour du - avaient été inversés, par exemple = -} , vous auriez supprimé silencieusement tous les caractères de l'ordinal 61 à 125 inclus, ce qui aurait inclus, avec un désordre de ponctuation, toutes les lettres ASCII standard, à la fois minuscules et majuscules. p>

Vous pouvez résoudre ce problème en supprimant simplement le deuxième - de votre classe de caractères (vous l'avez déjà inclus au début de la classe où il n'a pas besoin d'être échappé), en changeant de

import string
killpunctuation = str.maketrans('', '', string.punctuation)

to

text = text.translate(killpunctuation)

mais je vais suggérer de supprimer les expressions régulières ici; le risque d'erreurs avec beaucoup de ponctuation littérale est élevé, et il existe d'autres méthodes qui n'impliquent pas du tout de regex qui devraient fonctionner très bien et ne pas vous inquiéter si vous avez échappé à toutes les choses importantes (l'alternative est de sur-échapper, ce qui rend l'expression régulière illisible, et toujours sujette aux erreurs).

À la place, remplacez cette ligne par un simple appel str.translate . Tout d'abord, en dehors de la fonction, créez une table de traduction des éléments à supprimer :

text = re.sub(r"[-()\"#/@;:<>{}-=~|.?,]","",text)

puis remplacez la ligne:

# The redundant - is harmless here since the result is a dict which dedupes anyway
killpunctuation = str.maketrans('', '', r"-()\"#/@;:<>{}-=~|.?,")

par:

text = re.sub(r"[-()\"#/@;:<>{}=~|.?,]", "", text)

Il devrait fonctionner au moins aussi vite que l'expression régulière (probablement plus rapide), et il est beaucoup moins sujet aux erreurs, car aucun caractère n'a de signification particulière (les tables de traduction ne sont que des mappages d'ordinaires Unicode à Aucun , signifiant delete, un autre ordinal, signifiant le remplacement d'un seul caractère, ou une chaîne, signifiant char -> remplacement multichar; ils n'ont pas de concept d'échappements spéciaux). Si l'objectif est de tuer toutes les ponctuations ASCII, il vaut probablement mieux utiliser la constante du module string pour définir la table de traduction (ce qui rend également le code plus auto-documenté, donc les gens ne se demandent pas si vous supprimez tout ou juste une partie de la ponctuation, et si c'était intentionnel):

text = re.sub(r"[-()\"#/@;:<>{}-=~|.?,]", "", text)

En l'occurrence, votre chaîne existante ne supprime pas toute la ponctuation (elle manque, entre autres choses , ^ , ! , $ , etc.), donc ce changement peut ne pas être correct, mais s'il est correct, faites-le définitivement. Si c'est censé être un sous-ensemble de ponctuation, vous voulez certainement ajouter un commentaire sur la façon dont cette ponctuation a été choisie, donc les responsables ne se demandent pas si vous avez fait une erreur.


2 commentaires

merci, l'erreur a disparu mais pas la ponctuation


@olfamasmoudi: Ça devrait. Cependant, je ne peux pas parler des autres erreurs que votre code peut contenir.



1
votes

Utiliser ceci fonctionne comme pour moi

def clean_text(text):
    text = text.lower()
    text = re.sub('\[.*?\]', '', text)
    text = re.sub('https?://\S+|www\.\S+', '', text)
    text = re.sub('<.*?>+', '', text)
    text = re.sub('[%s]' % re.escape(string.punctuation), '', text)
    text = re.sub('\n', '', text)
    text = re.sub('\w*\d\w*', '', text)
    return text


0 commentaires