我强烈建议您将文件重新编码为 UTF-8。在 BMP 之外没有任何 Unicode 字符的很可能的情况下,您可以利用 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 中打开它。请解释一下。
被视为记录结束有点令人担忧。看起来0x85 被识别为 NEL(C1 控制代码,NEWLINE)。很有可能数据最初是用一些传统的单字节编码编码的,其中 0x85 有意义,但在原始编码是 ISO-8859-1 aka latin1 的错误假设下已被转码为 UTF-16。文件起源于哪里? IBM 大型机? Windows/Unix/经典 Mac?什么国家、地区、语言?您显然认为 不是换行符;你觉得这意味着什么?
请随时将一份精简文件(包括一些 内容)发送至sjmachin at lexicon dot net
更新基于提供的 1 行示例数据。
这证实了我的怀疑。阅读this。这是其中的一段话:
... 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,即保护区的起点(由面向块的终端使用。)
或
中文短跑
?
看起来有必要对更大的数据样本进行彻底分析。乐于助人。