web-dev-qa-db-fra.com

Écrire du texte Unicode dans un fichier texte?

Je extrait des données d'un document Google, les traite et les écris dans un fichier (que je vais éventuellement coller dans une page Wordpress).

Il a des symboles non-ASCII. Comment puis-je convertir ces symboles en toute sécurité en symboles pouvant être utilisés dans une source HTML?

Actuellement, je convertis tout le contenu en Unicode, en le réunissant dans une chaîne Python, puis en faisant:

import codecs
f = codecs.open('out.txt', mode="w", encoding="iso-8859-1")
f.write(all_html.encode("iso-8859-1", "replace"))

Il y a une erreur d'encodage sur la dernière ligne:

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

Solution partielle:

Ce Python s'exécute sans erreur:

row = [unicode(x.strip()) if x is not None else u'' for x in row]
all_html = row[0] + "<br/>" + row[1]
f = open('out.txt', 'w')
f.write(all_html.encode("utf-8"))

Mais ensuite, si j'ouvre le fichier texte, je vois beaucoup de symboles comme:

Qur’an 

Peut-être que j'ai besoin d'écrire sur autre chose qu'un fichier texte?

214
simon

Traitez le plus possible exclusivement avec des objets unicode en décodant des éléments en objets unicode lors de leur première acquisition et en les codant si nécessaire à la sortie.

Si votre chaîne est en réalité un objet unicode, vous devrez le convertir en objet chaîne encodé au format Unicode avant de l'écrire dans un fichier:

foo = u'Δ, Й, ק, ‎ م, ๗, あ, 叶, 葉, and 말.'
f = open('test', 'w')
f.write(foo.encode('utf8'))
f.close()

Lorsque vous relisez ce fichier, vous obtenez une chaîne codée au format Unicode que vous pouvez décoder en un objet Unicode:

f = file('test', 'r')
print f.read().decode('utf8')
306
quasistoic

Dans Python 2.6+, vous pourriez tiliser io.open() c'est la valeur par défaut ( Builtin open() ) sur Python 3:

import io

with io.open(filename, 'w', encoding=character_encoding) as file:
    file.write(unicode_text)

Cela peut être plus pratique si vous devez écrire le texte progressivement (vous n'avez pas besoin d'appeler plusieurs fois unicode_text.encode(character_encoding)). Contrairement au module codecs, le module io prend en charge les nouvelles lignes universelles.

67
jfs

La gestion des chaînes Unicode est déjà normalisée dans Python 3.

  1. les caractères sont déjà stockés dans la mémoire Unicode (32 bits)
  2. Vous devez seulement ouvrir le fichier dans utf-8
    (La conversion de 32 bits entre Unicode et UTF-8 est automatiquement effectuée de la mémoire au fichier.)

    out1 = "(嘉南大圳 ㄐㄧㄚ ㄋㄢˊ ㄉㄚˋ ㄗㄨㄣˋ )"
    fobj = open("t1.txt", "w", encoding="utf-8")
    fobj.write(out1)
    fobj.close()
    
25
david m lee

Le fichier ouvert par codecs.open est un fichier qui prend des données unicode, les code dans iso-8859-1 et les écrit dans le fichier. Cependant, ce que vous essayez d'écrire n'est pas unicode; vous prenez unicode et vous l'encodez dans iso-8859-1vous-même. C’est ce que fait la méthode unicode.encode et le résultat de l’encodage d’une chaîne unicode est une chaîne bytest (un type str.)

Vous devez soit utiliser la fonction normale open() et coder vous-même le code unicode, soit (généralement une meilleure idée) utiliser codecs.open() et not coder les données vous-même.

18
Thomas Wouters

Préface: votre téléspectateur va-t-il fonctionner?

Assurez-vous que votre lecteur/éditeur/terminal (quelle que soit votre interaction avec votre fichier encodé en utf-8) puisse lire le fichier. C'est souvent un problème sur Windows , par exemple, le Bloc-notes.

Écrire du texte Unicode dans un fichier texte?

Dans Python 2, utilisez open à partir du module io (il en va de même pour la fonction intégrée open dans Python 3):

import io

La meilleure pratique, en général, utilise UTF-8 pour écrire dans des fichiers (nous n'avons même pas à nous soucier de l'ordre des octets avec utf-8).

encoding = 'utf-8'

utf-8 est l'encodage le plus moderne et le plus universellement utilisable - il fonctionne dans tous les navigateurs Web, la plupart des éditeurs de texte (consultez vos paramètres si vous rencontrez des problèmes) et la plupart des terminaux/shells.

Sous Windows, vous pouvez essayer utf-16le si vous êtes limité à l'affichage de la sortie dans le Bloc-notes (ou dans un autre visualiseur limité).

encoding = 'utf-16le' # sorry, Windows users... :(

Et ouvrez-le simplement avec le gestionnaire de contexte et écrivez vos caractères unicode:

with io.open(filename, 'w', encoding=encoding) as f:
    f.write(unicode_object)

Exemple utilisant plusieurs caractères Unicode

Voici un exemple qui tente de mapper tous les caractères possibles d’une largeur maximale de trois bits (4 est le maximum, mais cela irait un peu loin) de la représentation numérique (en entiers) à une sortie imprimable codée, avec son nom, si possible (placez-le dans un fichier nommé uni.py):

from __future__ import print_function
import io
from unicodedata import name, category
from curses.ascii import controlnames
from collections import Counter

try: # use these if Python 2
    unicode_chr, range = unichr, xrange
except NameError: # Python 3
    unicode_chr = chr

exclude_categories = set(('Co', 'Cn'))
counts = Counter()
control_names = dict(enumerate(controlnames))
with io.open('unidata', 'w', encoding='utf-8') as f:
    for x in range((2**8)**3): 
        try:
            char = unicode_chr(x)
        except ValueError:
            continue # can't map to unicode, try next x
        cat = category(char)
        counts.update((cat,))
        if cat in exclude_categories:
            continue # get rid of noise & greatly shorten result file
        try:
            uname = name(char)
        except ValueError: # probably control character, don't use actual
            uname = control_names.get(x, '')
            f.write(u'{0:>6x} {1}    {2}\n'.format(x, cat, uname))
        else:
            f.write(u'{0:>6x} {1}  {2}  {3}\n'.format(x, cat, char, uname))
# may as well describe the types we logged.
for cat, count in counts.items():
    print('{0} chars of category, {1}'.format(count, cat))

Cela devrait durer environ une minute. Vous pouvez visualiser le fichier de données. Si votre visionneuse de fichiers peut afficher unicode, vous le verrez. Des informations sur les catégories peuvent être trouvées ici . Sur la base des chiffres, nous pouvons probablement améliorer nos résultats en excluant les catégories Cn et Co, qui ne sont associées à aucun symbole.

$ python uni.py

Il affichera le mappage hexadécimal, catégorie , le symbole (à moins que vous ne puissiez pas obtenir le nom, donc probablement un caractère de contrôle), et le nom du symbole. par exemple.

Je recommande less sous Unix ou Cygwin (n'imprimez pas/ne supprimez pas l'intégralité du fichier dans votre sortie):

$ less unidata

par exemple. affichera des lignes similaires aux lignes suivantes que j’ai échantillonnées à l’aide de Python 2 (unicode 5.2):

     0 Cc NUL
    20 Zs     SPACE
    21 Po  !  EXCLAMATION MARK
    b6 So  ¶  PILCROW SIGN
    d0 Lu  Ð  LATIN CAPITAL LETTER ETH
   e59 Nd  ๙  THAI DIGIT NINE
  2887 So  ⢇  BRAILLE PATTERN DOTS-1238
  bc13 Lo  밓  HANGUL SYLLABLE MIH
  ffeb Sm  →  HALFWIDTH RIGHTWARDS ARROW

Mon Python 3.5 d'Anaconda a unicode 8.0, je suppose que la plupart des 3 le seraient.

14
Aaron Hall

Comment imprimer des caractères Unicode dans un fichier:

Enregistrez ceci dans le fichier: foo.py:

#!/usr/bin/python -tt
# -*- coding: utf-8 -*-
import codecs
import sys 
UTF8Writer = codecs.getwriter('utf8')
sys.stdout = UTF8Writer(sys.stdout)
print(u'e with obfuscation: é')

Exécutez-le et dirigez la sortie vers le fichier:

python foo.py > tmp.txt

Ouvrez tmp.txt et regardez à l'intérieur, vous voyez ceci:

el@apollo:~$ cat tmp.txt 
e with obfuscation: é

Ainsi, vous avez enregistré unicode avec un repère d’obscurcissement dans un fichier.

3
Eric Leschinski

Cette erreur survient lorsque vous essayez de coder une chaîne non-unicode: elle tente de la décoder, en supposant que ce soit en ASCII brut. Il y a deux possibilités:

  1. Vous l'encodez en chaîne bytest, mais comme vous avez utilisé codecs.open, la méthode write attend un objet unicode. Donc, vous l'encodez et il essaie de le décoder à nouveau. Essayez: f.write(all_html) à la place.
  2. all_html n'est pas, en fait, un objet unicode. Quand vous faites .encode(...), il essaie d'abord de le décoder.
1
Thomas K

En cas d'écriture sur python3

>>> a = u'bats\u00E0'
>>> print a
batsà
>>> f = open("/tmp/test", "w")
>>> f.write(a)
>>> f.close()
>>> data = open("/tmp/test").read()
>>> data
'batsà'

En cas d'écriture sur python2:

>>> a = u'bats\u00E0'
>>> f = open("/tmp/test", "w")
>>> f.write(a)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

Pour éviter cette erreur, vous devez l'encoder en octets en utilisant les codecs "utf-8" comme ceci:

>>> f.write(a.encode("utf-8"))
>>> f.close()

et décodez les données en lisant à l'aide des codecs "utf-8":

>>> data = open("/tmp/test").read()
>>> data.decode("utf-8")
u'bats\xe0'

Et aussi si vous essayez d'exécuter une impression sur cette chaîne, elle sera automatiquement décodée à l'aide des codecs "utf-8" comme celui-ci.

>>> print a
batsà
0
ashish14