python - utf8 - ¿Escribir texto Unicode en un archivo de texto?
manejo de archivos binarios en python (7)
Estoy sacando datos de un documento de Google, procesándolos y escribiéndolos en un archivo (que eventualmente pegaré en una página de Wordpress).
Tiene algunos símbolos no ASCII. ¿Cómo puedo convertirlos de forma segura en símbolos que se pueden usar en una fuente HTML?
Actualmente estoy convirtiendo todo a Unicode en el camino, uniéndolo en una cadena de Python, y luego haciendo:
import codecs
f = codecs.open(''out.txt'', mode="w", encoding="iso-8859-1")
f.write(all_html.encode("iso-8859-1", "replace"))
Hay un error de codificación en la última línea:
UnicodeDecodeError: el codec ''ascii'' no puede decodificar el byte 0xa0 en la posición 12286: ordinal no está dentro del rango (128)
Solución parcial:
Este Python se ejecuta sin un error:
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")
Pero luego, si abro el archivo de texto real, veo muchos símbolos como:
Qur’an
Tal vez necesito escribir en algo que no sea un archivo de texto?
Prefacio: ¿tu visor funcionará?
Asegúrese de que su lector / editor / terminal (sin embargo, está interactuando con su archivo codificado en utf-8) puede leer el archivo. Esto suele ser un problema en Windows , por ejemplo, el Bloc de notas.
¿Escribir texto Unicode en un archivo de texto?
En Python 2, use open
desde el módulo io
(esto es lo mismo que el incorporado en Python 3):
import io
Las mejores prácticas, en general, usan UTF-8
para escribir en archivos (ni siquiera tenemos que preocuparnos por el orden de bytes con utf-8).
encoding = ''utf-8''
utf-8 es la codificación más moderna y de uso universal; funciona en todos los navegadores web, en la mayoría de los editores de texto (consulte su configuración si tiene problemas) y en la mayoría de los terminales / shells.
En Windows, puede probar utf-16le
si está limitado a ver los resultados en el Bloc de notas (u otro visor limitado).
encoding = ''utf-16le'' # sorry, Windows users... :(
Y solo ábrelo con el administrador de contexto y escribe tus caracteres Unicode:
with io.open(filename, ''w'', encoding=encoding) as f:
f.write(unicode_object)
Ejemplo usando muchos caracteres Unicode
Aquí hay un ejemplo que intenta mapear cada carácter posible de hasta tres bits de ancho (4 es el máximo, pero iría un poco más lejos) de la representación digital (en enteros) a una salida imprimible codificada, junto con su nombre, si posible (ponga esto en un archivo llamado 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))
Esto debería ejecutarse en el orden de aproximadamente un minuto, y puede ver el archivo de datos, y si su visor de archivos puede mostrar unicode, lo verá. La información sobre las categorías se puede encontrar here . Con base en los conteos, probablemente podamos mejorar nuestros resultados al excluir las categorías Cn y Co, que no tienen símbolos asociados con ellos.
$ python uni.py
Mostrará la asignación hexadecimal, la here , el símbolo (a menos que no pueda obtener el nombre, por lo que probablemente sea un carácter de control) y el nombre del símbolo. p.ej
Recomiendo less
en Unix o Cygwin (no imprima / envíe todo el archivo a su salida):
$ less unidata
por ejemplo, se mostrará similar a las siguientes líneas que muestreé usando 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
Mi Python 3.5 de Anaconda tiene unicode 8.0, supongo que la mayoría de los 3 lo sería.
El archivo abierto por codecs.open
es un archivo que toma datos unicode
, los codifica en iso-8859-1
y los escribe en el archivo. Sin embargo, lo que intentas escribir no es unicode
; usted toma unicode
y lo codifica en iso-8859-1
usted mismo . Eso es lo que hace el método unicode.encode
, y el resultado de codificar una cadena Unicode es un bytestring (un tipo str
).
Debe usar normal open()
y codificar el open()
Unicode, o (generalmente una mejor idea) usar codecs.open()
y no codificar los datos usted mismo.
El manejo de cadenas Unicode está estandarizado en Python 3.
- Char se almacenan en Unicode
Solo necesitas abrir el archivo en utf-8.
out1 = "(嘉南大圳 ㄐㄧㄚ ㄋㄢˊ ㄉㄚˋ ㄗㄨㄣˋ )" fobj = open("t1.txt", "w", encoding="utf-8") fobj.write(out1) fobj.close()
En Python 2.6+, puedes usar io.open()
que es predeterminado ( incorporado en open()
) en Python 3:
import io
with io.open(filename, ''w'', encoding=character_encoding) as file:
file.write(unicode_text)
Podría ser más conveniente si necesita escribir el texto de manera incremental (no necesita llamar a unicode_text.encode(character_encoding)
varias veces). A diferencia del módulo de codecs
, el módulo io
tiene un adecuado soporte para nuevas líneas universales.
Ese error surge cuando intentas codificar una cadena que no es Unicode: intenta decodificarla, asumiendo que está en ASCII simple. Hay dos posibilidades:
- Lo estás codificando en una serie de bytestring, pero debido a que has usado codecs.open, el método de escritura espera un objeto Unicode. Así que lo codificas, y trata de decodificarlo de nuevo. Intente:
f.write(all_html)
lugar. - all_html no es, de hecho, un objeto Unicode. Cuando haces
.encode(...)
, primero intenta decodificarlo.
Trate exclusivamente con objetos Unicode tanto como sea posible mediante la decodificación de cosas a objetos Unicode cuando los obtiene por primera vez y codifíquelos cuando sea necesario al salir.
Si su cadena es en realidad un objeto Unicode, deberá convertirla en un objeto de cadena codificada en Unicode antes de escribirlo en un archivo:
foo = u''Δ, Й, ק, م, ๗, あ, 叶, 葉, and 말.''
f = open(''test'', ''w'')
f.write(foo.encode(''utf8''))
f.close()
Cuando vuelvas a leer ese archivo, obtendrás una cadena codificada en Unicode que puedes decodificar en un objeto Unicode:
f = file(''test'', ''r'')
print f.read().decode(''utf8'')
Cómo imprimir caracteres Unicode en un archivo:
Guarda esto en el archivo: 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: é'')
Ejecutarlo y canalizar la salida al archivo:
python foo.py > tmp.txt
Abre tmp.txt y mira dentro, ves esto:
el@apollo:~$ cat tmp.txt
e with obfuscation: é
Por lo tanto, ha guardado unicode e con una marca de ofuscación en un archivo.