Lecture de caractères à partir d'un fichier en Python

102

Dans un fichier texte, il y a une chaîne "Je n'aime pas ça".

Cependant, quand je le lis dans une chaîne, cela devient "Je ne \ xe2 \ x80 \ x98t comme ça". Je comprends que \ u2018 est la représentation unicode de "'". j'utilise

f1 = open (file1, "r")
text = f1.read()

commande pour faire la lecture.

Maintenant, est-il possible de lire la chaîne de telle manière que lorsqu'elle est lue dans la chaîne, c'est "Je n'aime pas ça", au lieu de "Je ne \ xe2 \ x80 \ x98t comme ça comme ça"?

Deuxième édition: j'ai vu certaines personnes utiliser la cartographie pour résoudre ce problème, mais vraiment, n'y a-t-il pas de conversion intégrée qui effectue ce type de conversion ANSI en Unicode (et vice versa)?

Graviton
la source
Quelques commentaires: J'ai vu certaines personnes utiliser la cartographie pour résoudre ce problème, mais vraiment, n'y a-t-il pas de conversion intégrée qui effectue ce type de conversion ANSI en Unicode (et vice versa)? Merci!
Graviton
Il n'y en a pas, car il existe des centaines de milliers de points de code Unicode. Comment décideriez-vous qui doit être mappé à quels caractères ASCII?
John Millikin le
2
btw, votre fichier texte est cassé! U + 2018 est le "COTATION UNIQUE GAUCHE", pas une apostrophe (U + 0027 le plus souvent).
john, votre commentaire est faux, du moins dans le sens général. la lib iconv peut être utilisée pour translittérer des caractères unicode en ascii (même dépendant de la locale. $ python -c 'print u "\ u2018" .encode ("utf-8")' | iconv -t 'ascii // translit' | xxd 0000000: 270a
le fait est que vous devez convertir UNICODE en ASCII (et non l'inverse).
hasen

Réponses:

157

Réf: http://docs.python.org/howto/unicode

La lecture d'Unicode à partir d'un fichier est donc simple:

import codecs
with codecs.open('unicode.rst', encoding='utf-8') as f:
    for line in f:
        print repr(line)

Il est également possible d'ouvrir des fichiers en mode mise à jour, permettant à la fois la lecture et l'écriture:

with codecs.open('test', encoding='utf-8', mode='w+') as f:
    f.write(u'\u4500 blah blah blah\n')
    f.seek(0)
    print repr(f.readline()[:1])

EDIT : Je suppose que votre objectif est simplement de pouvoir lire correctement le fichier dans une chaîne en Python. Si vous essayez de convertir une chaîne ASCII à partir d'Unicode, il n'y a vraiment aucun moyen direct de le faire, car les caractères Unicode n'existeront pas nécessairement en ASCII.

Si vous essayez de convertir une chaîne ASCII, essayez l'une des méthodes suivantes:

  1. Remplacez les caractères Unicode spécifiques par des équivalents ASCII, si vous ne cherchez à gérer que quelques cas particuliers tels que cet exemple particulier

  2. Utilisez le unicodedatamodule normalize()et la string.encode()méthode pour convertir au mieux votre équivalent ASCII le plus proche (Réf https://web.archive.org/web/20090228203858/http://techxplorer.com/2006/07/18/converting- unicode à ascii en utilisant python ):

    >>> teststr
    u'I don\xe2\x80\x98t like this'
    >>> unicodedata.normalize('NFKD', teststr).encode('ascii', 'ignore')
    'I donat like this'
Geai
la source
3
codecsLe module ne gère pas correctement le mode de retour à la ligne universel. Utilisez io.open()plutôt sur Python 2.7+ (il est intégré open()à Python 3).
jfs
15

Il y a quelques points à considérer.

Un caractère \ u2018 peut apparaître uniquement comme un fragment de représentation d'une chaîne Unicode en Python, par exemple si vous écrivez:

>>> text = u'‘'
>>> print repr(text)
u'\u2018'

Maintenant, si vous voulez simplement imprimer joliment la chaîne unicode, utilisez simplement la encodeméthode unicode :

>>> text = u'I don\u2018t like this'
>>> print text.encode('utf-8')
I dont like this

Pour vous assurer que chaque ligne de n'importe quel fichier sera lue comme unicode, vous feriez mieux d'utiliser la codecs.openfonction au lieu de juste open, ce qui vous permet de spécifier le codage du fichier:

>>> import codecs
>>> f1 = codecs.open(file1, "r", "utf-8")
>>> text = f1.read()
>>> print type(text)
<type 'unicode'>
>>> print text.encode('utf-8')
I dont like this
DzinX
la source
6

Mais c'est vraiment "je n'aime pas ça" et non "je n'aime pas ça". Le caractère u '\ u2018' est un caractère complètement différent de "'" (et, visuellement, devrait correspondre davantage à' `').

Si vous essayez de convertir unicode encodé en ASCII brut, vous pouvez peut-être conserver un mappage de ponctuation Unicode que vous souhaitez traduire en ASCII.

punctuation = {
  u'\u2018': "'",
  u'\u2019': "'",
}
for src, dest in punctuation.iteritems():
  text = text.replace(src, dest)

Cependant, il y a énormément de caractères de ponctuation en Unicode , mais je suppose que vous pouvez compter sur seulement quelques-uns d'entre eux utilisés par l'application qui crée les documents que vous lisez.

Logan
la source
1
en fait, si vous faites mapper les ordinaux Unicode de dict aux ordinaux Unicode ({0x2018: 0x27, 0x2019: 0x27}), vous pouvez simplement passer le dict entier à text.translate () pour faire tout le remplacement en une seule fois.
Thomas Wouters
5

Il est également possible de lire un fichier texte encodé à l'aide de la méthode de lecture python 3:

f = open (file.txt, 'r', encoding='utf-8')
text = f.read()
f.close()

Avec cette variante, il n'est pas nécessaire d'importer des bibliothèques supplémentaires

Stein
la source
3

En laissant de côté le fait que votre fichier texte est cassé (U + 2018 est un guillemet gauche, pas une apostrophe): iconv peut être utilisé pour translittérer des caractères unicode en ascii.

Vous devrez google pour "iconvcodec", car le module ne semble plus être pris en charge et je ne trouve pas de page d'accueil canonique pour cela.

>>> import iconvcodec
>>> from locale import setlocale, LC_ALL
>>> setlocale(LC_ALL, '')
>>> u'\u2018'.encode('ascii//translit')
"'"

Vous pouvez également utiliser l' iconvutilitaire de ligne de commande pour nettoyer votre fichier:

$ xxd foo
0000000: e280 980a                                ....
$ iconv -t 'ascii//translit' foo | xxd
0000000: 270a                                     '.

la source
2

Il est possible que vous ayez une chaîne non-unicode avec des caractères d'échappement unicode, par exemple:

>>> print repr(text)
'I don\\u2018t like this'

Cela m'est arrivé une fois auparavant. Vous pouvez utiliser un unicode_escapecodec pour décoder la chaîne en unicode, puis l'encoder dans le format de votre choix:

>>> uni = text.decode('unicode_escape')
>>> print type(uni)
<type 'unicode'>
>>> print uni.encode('utf-8')
I dont like this
DzinX
la source
1

C'est la manière Pythons de vous montrer des chaînes encodées en unicode. Mais je pense que vous devriez pouvoir imprimer la chaîne à l'écran ou l'écrire dans un nouveau fichier sans aucun problème.

>>> test = u"I don\u2018t like this"
>>> test
u'I don\u2018t like this'
>>> print test
I dont like this
xardias
la source
1

En fait, U + 2018 est la représentation Unicode du caractère spécial '. Si vous le souhaitez, vous pouvez convertir les instances de ce caractère en U + 0027 avec ce code:

text = text.replace (u"\u2018", "'")

De plus, qu'utilisez-vous pour écrire le fichier? f1.read()devrait retourner une chaîne qui ressemble à ceci:

'I don\xe2\x80\x98t like this'

S'il renvoie cette chaîne, le fichier est mal écrit:

'I don\u2018t like this'
John Millikin
la source
Désolé! Comme vous l'avez dit, il retourne `` Je ne \ xe2 \ x80 \ x98t comme ça ''
Graviton
Le 'Je ne \ xe2 \ x80 \ x98t comme ça' que vous voyez est ce que Python appellerait un str. Cela semble être le codage utf-8 de u'Je ne suis pas comme ça ', qui est une instance Unicode en Python. Essayez d'appeler .decode ('utf-8') sur le premier ou .encode ('utf-8') sur le second.
Logan le
@hop: oups, j'ai oublié ord () renvoie décimal au lieu de hex. Merci pour la capture.
John Millikin