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)?


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'

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

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.


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


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                                     '.

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

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

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'

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.