Le sugiero que recodifique sus archivos a UTF-8. En la condición muy probable de que no tenga ningún carácter Unicode fuera del BMP, puede aprovechar el hecho de que UTF-16 es una codificación de longitud fija para leer bloques de longitud fija desde su archivo de entrada sin preocuparse por el bloqueo a horcajadas límites.
Paso 1: Determine qué codificación tiene en realidad.Examinar los primeros bytes del archivo:
print repr(open('thefile.csv', 'rb').read(100))
cuatro posibles formas de codificación u'abc'
\xfe\xff\x00a\x00b\x00c -> utf_16
\xff\xfea\x00b\x00c\x00 -> utf_16
\x00a\x00b\x00c -> utf_16_be
a\x00b\x00c\x00 -> utf_16_le
Si usted tiene algún problema con este paso, editar su pregunta para incluir los resultados de las anteriores print repr()
Paso 2: Aquí hay un Python 2.X recodificar-UTF-16 * -to-UTF-8 script:
import sys
infname, outfname, enc = sys.argv[1:4]
fi = open(infname, 'rb')
fo = open(outfname, 'wb')
BUFSIZ = 64 * 1024 * 1024
first = True
while 1:
buf = fi.read(BUFSIZ)
if not buf: break
if first and enc == 'utf_16':
bom = buf[:2]
buf = buf[2:]
enc = {'\xfe\xff': 'utf_16_be', '\xff\xfe': 'utf_16_le'}[bom]
# KeyError means file doesn't start with a valid BOM
first = False
fo.write(buf.decode(enc).encode('utf8'))
fi.close()
fo.close()
Otros asuntos:
podría decir que los archivos son demasiado grandes para leer el archivo completo, recodificar y volver a escribir, sin embargo, puede abrirlo en vi
. Por favor explique.
El < 85> Ser tratado como fin de registro es un poco preocupante. Parece que 0x85
se reconoce como NEL (código de control C1, NEWLINE). Existe una gran posibilidad de que los datos estuvieran originalmente codificados en alguna codificación heredada de un byte, donde 0x85 tiene un significado pero ha sido transcodificado a UTF-16 bajo la falsa suposición de que la codificación original era ISO-8859-1 también conocida como latin1. ¿De dónde se originó el archivo? ¿Un mainframe de IBM? Windows/Unix/classic Mac? ¿Qué país, lugar, idioma? Usted obviamente piensa que el < 85> no está destinado a ser una nueva línea; ¿Qué piensas que significa?
dude en enviar una copia de un archivo de corte hacia abajo (que incluye algunos de los < 85> cosas) a sjmachin at lexicon dot net
actualización basado en datos de la muestra 1-linea provistos.
Esto confirma mis sospechas. Lee this. He aquí una cita de él:
... the C1 control characters ... are rarely used directly, except on specific platforms such as OpenVMS. When they turn up in documents, Web pages, e-mail messages, etc., which are ostensibly in an ISO-8859-n encoding, their code positions generally refer instead to the characters at that position in a proprietary, system-specific encoding such as Windows-1252 or the Apple Macintosh ("MacRoman") character set that use the codes provided for representation of the C1 set with a single 8-bit byte to instead provide additional graphic characters
este código:
s1 = '\xff\xfe1\x00,\x002\x00,\x00G\x00,\x00S\x00,\x00H\x00 \x00f\x00\xfc\x00r\x00 \x00e\x00 \x00\x96\x00 \x00m\x00 \x00\x85\x00,\x00,\x00I\x00\r\x00\n\x00'
s2 = s1.decode('utf16')
print 's2 repr:', repr(s2)
from unicodedata import name
from collections import Counter
non_ascii = Counter(c for c in s2 if c >= u'\x80')
print 'non_ascii:', non_ascii
for c in non_ascii:
print "from: U+%04X %s" % (ord(c), name(c, "<no name>"))
c2 = c.encode('latin1').decode('cp1252')
print "to: U+%04X %s" % (ord(c2), name(c2, "<no name>"))
s3 = u''.join(
c.encode('latin1').decode('1252') if u'\x80' <= c < u'\xA0' else c
for c in s2
)
print 's3 repr:', repr(s3)
print 's3:', s3
produce lo siguiente (Python 2.7.2 IDLE, Windows 7):
s2 repr: u'1,2,G,S,H f\xfcr e \x96 m \x85,,I\r\n'
non_ascii: Counter({u'\x85': 1, u'\xfc': 1, u'\x96': 1})
from: U+0085 <no name>
to: U+2026 HORIZONTAL ELLIPSIS
from: U+00FC LATIN SMALL LETTER U WITH DIAERESIS
to: U+00FC LATIN SMALL LETTER U WITH DIAERESIS
from: U+0096 <no name>
to: U+2013 EN DASH
s3 repr: u'1,2,G,S,H f\xfcr e \u2013 m \u2026,,I\r\n'
s3: 1,2,G,S,H für e – m …,,I
¿Qué lo hace pensar es una interpretación más razonable de \x96
:
SPA es decir, inicio del área protegida (Utilizado por el bloque-ori Terminales ented.)
o
EN DASH
?
Parece que se justifica un análisis exhaustivo de una muestra de datos mucho mayor. Feliz de ayudar.
Gracias @phihag por su respuesta. ¿Hay alguna manera de hacer esto sin cargar el archivo en la memoria? Mi archivo csv es enorme. – venky
@venky Actualizado con un truco que debería funcionar en 2.x. – phihag
¿cómo sé si el archivo está comenzando con una lista de [email protected] – venky