Я настоятельно рекомендую вам перекодировать ваши файлы в UTF-8. При весьма вероятном условии, что у вас нет символов Unicode вне BMP, вы можете воспользоваться тем фактом, что UTF-16 является кодировкой фиксированной длины, чтобы считывать блоки фиксированной длины из вашего входного файла, не беспокоясь о блок-блоке. границы.
Шаг 1: Определите, какая кодировка у вас есть на самом деле. Изучите первые несколько байтов вашего файла:
print repr(open('thefile.csv', 'rb').read(100))
Четыре возможных способа кодирования 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
Если у вас возникли проблемы с этим шагом, отредактируйте свой вопрос, включив в него результаты вышеупомянутого print repr()
Шаг 2: Вот скрипт Python 2.X recode-UTF-16 * -to-UTF-8:
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()
Прочие вопросы:
Вы говорите, что ваши файлы слишком большие, чтобы прочитать весь файл, перекодировать и переписать, но вы можете открыть его в vi
. Пожалуйста, объясните.
<85>, который рассматривается как конец записи, немного беспокоит. Похоже, 0x85
распознается как NEL (управляющий код C1, NEWLINE). Существует большая вероятность того, что данные первоначально были закодированы в некоем устаревшем однобайтовом кодировании, где значение 0x85 имеет значение, но было перекодировано в UTF-16 при ложном предположении, что исходное кодирование было ISO-8859-1 или латинским1. Откуда появился файл? Мэйнфрейм IBM? Windows / Unix / классический Mac? Какая страна, язык, язык? Вы, очевидно, думаете, что <85> не означает перевод строки; что вы думаете, что это значит?
Пожалуйста, не стесняйтесь отправить копию сокращенного файла (который включает в себя некоторые из <85> материалов) на sjmachin at lexicon dot net
Обновление на основе предоставленных данных из 1 строки.
Это подтверждает мои подозрения. Прочитайте это . Вот цитата из него:
... управляющие символы C1 ... редко используются напрямую, кроме
конкретные платформы, такие как OpenVMS. Когда они появляются в документах,
Веб-страницы, сообщения электронной почты и т. Д., Которые якобы находятся в
ISO-8859-n, их кодовые позиции обычно обозначают вместо
символы в этой позиции в проприетарной, специфичной для системы
кодирование, например, Windows-1252 или Apple Macintosh («MacRoman»)
набор символов, использующий коды, представленные для представления C1
установить с одним 8-битным байтом, чтобы вместо этого обеспечить дополнительную графику
символы
Этот код:
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
производит следующее (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
Как вы думаете, что является более разумным толкованием \x96
:
SPA, т. Е. Начало защищенной зоны (используется терминалами с блочной ориентацией).
или
EN DASH
Похоже, что тщательный анализ гораздо большей выборки данных оправдан. Рад помочь.