UnicodeDecodeError: le codec 'ascii' ne peut pas décoder l'octet 0xe2 en position 13: ordinal pas dans la plage (128)

129

J'utilise NLTK pour effectuer un clustering kmeans sur mon fichier texte dans lequel chaque ligne est considérée comme un document. Par exemple, mon fichier texte ressemble à ceci:

belong finger death punch <br>
hasty <br>
mike hasty walls jericho <br>
jägermeister rules <br>
rules bands follow performing jägermeister stage <br>
approach 

Maintenant, le code de démonstration que j'essaie d'exécuter est le suivant:

import sys

import numpy
from nltk.cluster import KMeansClusterer, GAAClusterer, euclidean_distance
import nltk.corpus
from nltk import decorators
import nltk.stem

stemmer_func = nltk.stem.EnglishStemmer().stem
stopwords = set(nltk.corpus.stopwords.words('english'))

@decorators.memoize
def normalize_word(word):
    return stemmer_func(word.lower())

def get_words(titles):
    words = set()
    for title in job_titles:
        for word in title.split():
            words.add(normalize_word(word))
    return list(words)

@decorators.memoize
def vectorspaced(title):
    title_components = [normalize_word(word) for word in title.split()]
    return numpy.array([
        word in title_components and not word in stopwords
        for word in words], numpy.short)

if __name__ == '__main__':

    filename = 'example.txt'
    if len(sys.argv) == 2:
        filename = sys.argv[1]

    with open(filename) as title_file:

        job_titles = [line.strip() for line in title_file.readlines()]

        words = get_words(job_titles)

        # cluster = KMeansClusterer(5, euclidean_distance)
        cluster = GAAClusterer(5)
        cluster.cluster([vectorspaced(title) for title in job_titles if title])

        # NOTE: This is inefficient, cluster.classify should really just be
        # called when you are classifying previously unseen examples!
        classified_examples = [
                cluster.classify(vectorspaced(title)) for title in job_titles
            ]

        for cluster_id, title in sorted(zip(classified_examples, job_titles)):
            print cluster_id, title

(que vous pouvez également trouver ici )

L'erreur que je reçois est la suivante:

Traceback (most recent call last):
File "cluster_example.py", line 40, in
words = get_words(job_titles)
File "cluster_example.py", line 20, in get_words
words.add(normalize_word(word))
File "", line 1, in
File "/usr/local/lib/python2.7/dist-packages/nltk/decorators.py", line 183, in memoize
result = func(*args)
File "cluster_example.py", line 14, in normalize_word
return stemmer_func(word.lower())
File "/usr/local/lib/python2.7/dist-packages/nltk/stem/snowball.py", line 694, in stem
word = (word.replace(u"\u2019", u"\x27")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 13: ordinal not in range(128)

Que se passe-t-il ici?

user2602812
la source

Réponses:

133

Le fichier est lu comme un groupe de strs, mais il devrait s'agir de unicodes. Python essaie de convertir implicitement, mais échoue. Changement:

job_titles = [line.strip() for line in title_file.readlines()]

pour décoder explicitement le strs en unicode(ici en supposant UTF-8):

job_titles = [line.decode('utf-8').strip() for line in title_file.readlines()]

Il pourrait également être résolu en important le codecsmodule et en utilisant codecs.openplutôt que le fichier intégré open.

icktoofay
la source
2
exécuter ce line.decode ('utf-8'). strip (). lower (). split () me donne également la même erreur. J'ai ajouté le .deocode ('utf-8')
Aman Mathur
@kathirraja: Pouvez-vous fournir une référence à ce sujet? Autant que je sache, même dans Python 3, la decodeméthode reste le moyen préféré pour décoder une chaîne d'octets en une chaîne Unicode. (Bien que les types de ma réponse ne soient pas appropriés pour Python 3 - pour Python 3, nous essayons de convertir de bytesvers strplutôt que de strvers unicode.)
icktoofay
52

Cela fonctionne bien pour moi.

f = open(file_path, 'r+', encoding="utf-8")

Vous pouvez ajouter un troisième encodage de paramètre pour vous assurer que le type d'encodage est 'utf-8'

Remarque: cette méthode fonctionne très bien en Python3, je ne l'ai pas essayée en Python2.7.

uestcfei
la source
Cela ne fonctionne pas en Python 2.7.10:TypeError: 'encoding' is an invalid keyword argument for this function
Borhan Kazimipour
2
Cela ne fonctionne pas en Python 2.7.10: TypeError: 'encoding' is an invalid keyword argument for this function Cela fonctionne bien:import io with io.open(file_path, 'r', encoding="utf-8") as f: for line in f: do_something(line)
Borhan Kazimipour
2
A travaillé comme un charme en python3.6 Merci beaucoup!
SRC
32

Pour moi, il y avait un problème avec le codage du terminal. L'ajout de UTF-8 à .bashrc a résolu le problème:

export LC_CTYPE=en_US.UTF-8

N'oubliez pas de recharger .bashrc par la suite:

source ~/.bashrc
Georgi Karadzhov
la source
3
J'ai dû utiliser export LC_ALL=C.UTF-8sur Ubuntu 18.04.3 et Python 3.6.8. Sinon, cela a résolu mon problème, merci.
jbaranski
31

Vous pouvez également essayer ceci:

import sys
reload(sys)
sys.setdefaultencoding('utf8')
Siva S
la source
3
Quelles sont les conséquences de cela? Il semble que ce soit quelque chose de global et pas seulement applicable à ce fichier.
simeg
2
Notez que ce qui précède est obsolète dans Python 3.
gented
12

Sur Ubuntu 18.04 en utilisant Python3.6, j'ai résolu le problème en faisant les deux:

with open(filename, encoding="utf-8") as lines:

et si vous exécutez l'outil en ligne de commande:

export LC_ALL=C.UTF-8

Notez que si vous êtes en Python2.7, vous devez gérer cela différemment. Vous devez d'abord définir l'encodage par défaut:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

puis pour charger le fichier, vous devez utiliser io.openpour définir l'encodage:

import io
with io.open(filename, 'r', encoding='utf-8') as lines:

Vous devez toujours exporter l'environnement

export LC_ALL=C.UTF-8
Loretoparisi
la source
6

J'ai eu cette erreur en essayant d'installer un package python dans un conteneur Docker. Pour moi, le problème était que l'image du docker n'avait pas de localefichier. L'ajout du code suivant au Dockerfile a résolu le problème pour moi.

# Avoid ascii errors when reading files in Python
RUN apt-get install -y \
  locales && \
  locale-gen en_US.UTF-8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
Jacob Stern
la source
J'ai dû utiliser ceci: github.com/docker-library/python/issues/13
mayrop le
3

Pour rechercher TOUTES les erreurs Unicode liées ... À l'aide de la commande suivante:

grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

J'ai trouvé le mien dans

/etc/letsencrypt/options-ssl-nginx.conf:        # The following CSP directives don't use default-src as 

En utilisant shed, j'ai trouvé la séquence offensante. Cela s'est avéré être une erreur de l'éditeur.

00008099:     C2  194 302 11000010
00008100:     A0  160 240 10100000
00008101:  d  64  100 144 01100100
00008102:  e  65  101 145 01100101
00008103:  f  66  102 146 01100110
00008104:  a  61  097 141 01100001
00008105:  u  75  117 165 01110101
00008106:  l  6C  108 154 01101100
00008107:  t  74  116 164 01110100
00008108:  -  2D  045 055 00101101
00008109:  s  73  115 163 01110011
00008110:  r  72  114 162 01110010
00008111:  c  63  099 143 01100011
00008112:     C2  194 302 11000010
00008113:     A0  160 240 10100000
John Greene
la source
1

Vous pouvez essayer ceci avant d'utiliser la job_titleschaîne:

source = unicode(job_titles, 'utf-8')
Aminah Nuraini
la source
0

Pour python 3, l'encodage par défaut serait "utf-8". Les étapes suivantes sont suggérées dans la documentation de base: https://docs.python.org/2/library/csv.html#csv-examples en cas de problème

  1. Créer une fonction

    def utf_8_encoder(unicode_csv_data):
        for line in unicode_csv_data:
            yield line.encode('utf-8')
  2. Ensuite, utilisez la fonction à l'intérieur du lecteur, par exemple

    csv_reader = csv.reader(utf_8_encoder(unicode_csv_data))
Iamigham
la source
0

python3x ou supérieur

  1. charger le fichier dans le flux d'octets:

    body = '' pour les lignes en open ('website / index.html', 'rb'): decodedLine = lines.decode ('utf-8') body = body + decodedLine.strip () return body

  2. utiliser le paramètre global:

    import io import sys sys.stdout = io.TextIOWrapper (sys.stdout.buffer, encoding = 'utf-8')

io grand
la source
0

Utilisez open(fn, 'rb').read().decode('utf-8')au lieu de simplementopen(fn).read()

Ganesh Kharad
la source