Lectura de caracteres de un archivo en Python

102

En un archivo de texto, hay una cadena "No me gusta esto".

Sin embargo, cuando lo leo en una cadena, se convierte en "No me gusta esto \ xe2 \ x80 \ x98t". Entiendo que \ u2018 es la representación Unicode de "'". yo suelo

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

comando para hacer la lectura.

Ahora, ¿es posible leer la cadena de tal manera que cuando se lea en la cadena, sea "No me gusta esto", en lugar de "No me gusta \ xe2 \ x80 \ x98t así"?

Segunda edición: He visto a algunas personas usar el mapeo para resolver este problema, pero realmente, ¿no hay una conversión incorporada que haga este tipo de conversión de ANSI a Unicode (y viceversa)?

Graviton
fuente
Algunos comentarios: He visto a algunas personas usar el mapeo para resolver este problema, pero realmente, ¿no hay una conversión incorporada que haga este tipo de conversión de ANSI a Unicode (y viceversa)? ¡Gracias!
Graviton
No lo hay, porque hay cientos de miles de puntos de código Unicode. ¿Cómo decidiría cuál debería asignarse a qué caracteres ASCII?
John Millikin
2
por cierto, ¡tu archivo de texto está roto! U + 2018 es la "MARCA DE COTIZACIÓN ÚNICA IZQUIERDA", no un apóstrofo (U + 0027 más comúnmente).
John, tu comentario es incorrecto, al menos en el sentido general. la biblioteca iconv se puede usar para transliterar caracteres unicode a ascii (incluso dependiendo de la configuración regional. $ python -c 'print u "\ u2018" .encode ("utf-8")' | iconv -t 'ascii // translit' | xxd 0000000: 270a
la cosa es que necesitas convertir UNICODE a ASCII (no al revés).
Hasen

Respuestas:

157

Ref: http://docs.python.org/howto/unicode

Por lo tanto, leer Unicode de un archivo es simple:

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

También es posible abrir archivos en modo de actualización, permitiendo tanto leer como escribir:

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

EDITAR : Supongo que su objetivo previsto es solo poder leer el archivo correctamente en una cadena en Python. Si está intentando convertir a una cadena ASCII desde Unicode, entonces realmente no hay una forma directa de hacerlo, ya que los caracteres Unicode no necesariamente existirán en ASCII.

Si está intentando convertir a una cadena ASCII, pruebe una de las siguientes opciones:

  1. Reemplace los caracteres Unicode específicos con equivalentes ASCII, si solo está buscando manejar algunos casos especiales como este ejemplo en particular

  2. Utilice el unicodedatamódulo normalize()y el string.encode()método para convertir lo mejor que pueda al siguiente equivalente ASCII más cercano (Ref https://web.archive.org/web/20090228203858/http://techxplorer.com/2006/07/18/converting- unicode-a-ascii-usando-python ):

    >>> teststr
    u'I don\xe2\x80\x98t like this'
    >>> unicodedata.normalize('NFKD', teststr).encode('ascii', 'ignore')
    'I donat like this'
Arrendajo
fuente
3
codecsEl módulo no maneja correctamente el modo de nueva línea universal. Úselo en su io.open()lugar en Python 2.7+ (está integrado open()en Python 3).
jfs
15

Hay algunos puntos a considerar.

Un carácter \ u2018 puede aparecer solo como un fragmento de representación de una cadena Unicode en Python, por ejemplo, si escribe:

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

Ahora, si simplemente desea imprimir la cadena Unicode de manera bonita, simplemente use el encodemétodo Unicode :

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

Para asegurarse de que cada línea de cualquier archivo se lea como Unicode, es mejor que use la codecs.openfunción en lugar de solo open, lo que le permite especificar la codificación del archivo:

>>> 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
fuente
6

Pero realmente es "No me gusta esto" y no "No me gusta esto". El carácter u '\ u2018' es un carácter completamente diferente a "'" (y, visualmente, debería corresponder más a' `').

Si está tratando de convertir unicode codificado en ASCII simple, tal vez podría mantener un mapeo de puntuación Unicode que le gustaría traducir a ASCII.

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

Sin embargo, hay una gran cantidad de caracteres de puntuación en Unicode , pero supongo que puede contar con que solo algunos de ellos sean utilizados por cualquier aplicación que esté creando los documentos que está leyendo.

Logan
fuente
1
en realidad, si hace que el dict asigne ordinales Unicode a ordinales Unicode ({0x2018: 0x27, 0x2019: 0x27}), puede pasar el dict completo a text.translate () para hacer todo el reemplazo de una vez.
Thomas Wouters
5

También es posible leer un archivo de texto codificado usando el método de lectura de Python 3:

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

Con esta variación, no es necesario importar bibliotecas adicionales

Stein
fuente
3

Dejando a un lado el hecho de que su archivo de texto está roto (U + 2018 es una comilla izquierda, no un apóstrofe): iconv se puede usar para transliterar caracteres Unicode a ASCII.

Tendrá que buscar en Google "iconvcodec", ya que el módulo parece que ya no es compatible y no puedo encontrar una página de inicio canónica para él.

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

Alternativamente, puede usar la iconvutilidad de línea de comando para limpiar su archivo:

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

fuente
2

Existe la posibilidad de que de alguna manera tenga una cadena no Unicode con caracteres de escape Unicode, por ejemplo:

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

En realidad, esto me pasó una vez antes. Puede usar un unicode_escapecódec para decodificar la cadena en Unicode y luego codificarla en el formato que desee:

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

Esta es la forma en que Python le muestra cadenas codificadas en Unicode. Pero creo que debería poder imprimir la cadena en la pantalla o escribirla en un nuevo archivo sin ningún problema.

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

En realidad, U + 2018 es la representación Unicode del carácter especial '. Si lo desea, puede convertir instancias de ese carácter a U + 0027 con este código:

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

Además, ¿qué estás usando para escribir el archivo? f1.read()debería devolver una cadena que se parece a esto:

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

Si devuelve esta cadena, el archivo se está escribiendo incorrectamente:

'I don\u2018t like this'
John Millikin
fuente
¡Lo siento! Como dijiste, está devolviendo 'No me gusta esto \ xe2 \ x80 \ x98t'
Graviton
El 'No me gusta esto \ xe2 \ x80 \ x98t' que estás viendo es lo que Python llamaría str. Parece ser la codificación utf-8 de u'I don \ u2018t like this ', que es una instancia Unicode en Python. Intente llamar .decode ('utf-8') en el primero o .encode ('utf-8') en el último.
Logan
@hop: oops, olvidé ord () devuelve decimal en lugar de hexadecimal. Gracias por la captura.
John Millikin