我强烈建议你重新编码为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重新编码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又名latin1的情况下已被转码为UTF-16。文件来自哪里?一台IBM大型机? Windows/Unix /经典Mac?什么国家,地区,语言?你显然认为这并不意味着是一个换行符;你认为这意味着什么?
请随时切下文件的副本(包括一些< 85>的东西)的基础上提供了1行样本数据发送到sjmachin at lexicon dot net
更新。
这证实了我的怀疑。阅读this。下面是它报价:
... 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
此代码:
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即受保护区域的开始(block-ori使用)
或
EN DASH
?
看起来像一个更大的数据样本的彻底分析是有保证的。乐于帮助。
感谢@phihag的回复。有没有办法做到这一点,而无需将文件加载到内存中?我的csv文件很大。 – venky 2012-02-07 14:53:27
@venky更新了应该在2.x中工作的黑客。 – phihag 2012-02-07 15:02:45
如何知道文件是否以BOM开头?@phihag – venky 2012-02-07 15:15:32