"""...GB18030。我认为这将是解决方案,因为它能够读取前几个文件并正确解码。"""--请解释一下你的意思。对我来说,成功解码有两个标准:首先是raw_bytes.decode('some_encoding')不会失败,其次是当显示结果时,产生的Unicode在特定语言中是有意义的。使用
latin1
也就是
iso_8859_1
解码,宇宙中的每个文件都将通过第一个测试。大多数使用中文、日文和韩文的文件可以通过使用
gb18030
进行第一个测试,因为中文、日文和韩文中经常使用的字符大多使用相同的双字节序列块进行编码。你已经完成了第二个测试的多少部分呢?
不要在IDE或文本编辑器中查看数据。在Web浏览器中查看数据;它们通常更好地检测编码。
你怎么知道它是欧元符号?通过查看解码原始字节的文本编辑器屏幕上的内容,使用的是什么编码?cp1252?
你怎么知道它包含中文字符?你确定它不是日文或韩文吗?你从哪里得到的?
在香港、台湾、澳门和其他离岸地区创建的中文文件使用
big5
或
big5_hkscs
编码--尝试一下。
无论如何,采纳Mark的建议,将
chardet
指向它;如果文件足够大且正确编码为中文、日文或韩文,则
chardet
通常能够很好地检测所使用的编码--但是,如果有人在文本编辑器中手动编辑文件并使用单字节字符集,那么几个非法字符可能导致未检测到用于其他99.9%字符的编码。
你可以尝试对来自文件的5行数据执行
print repr(line)
,并将输出编辑到你的问题中。
如果文件不保密,你可以提供下载。
文件是在Windows上创建的吗?你如何在Python中读取它?(显示代码)
在OP评论之后进行更新:
记事本等不会尝试猜测编码;"ANSI"是默认值。你必须告诉它该怎么做。你所谓的欧元符号是原始字节"\x80",由你的编辑器使用你的环境的默认编码解码--通常是"cp1252"。不要使用这样的编辑器编辑你的文件。
早些时候,你谈到了“前几个错误”。现在你说你总共有5个错误。请解释一下。
如果文件确实几乎正确为gb18030,则应该能够逐行解码文件,当出现此类错误时,请捕获它,打印错误消息,从消息中提取字节偏移量,打印repr(two_bad_bytes),然后继续进行。我非常想知道这两个字节中的哪一个字节出现了
\x80
。如果根本没有出现,则“欧元符号”不是您问题的一部分。请注意,
\x80
可以有效地出现在gb18030文件中,但只能作为以
\x81
至
\xfe
开头的2字节序列的第2个字节。
在尝试修复问题之前,最好知道您的问题是什么。在“ANSI”模式下使用记事本等来猛击它并不是一个好主意。
您一直对如何确定gb18030解码结果有所保留。特别是,我将密切关注gbk失败但gb18030“正常工作”的行 - 其中必须存在一些极为罕见的中文字符,或者可能是一些非中文非ASCII字符...
以下是一种更好的检查方法:使用raw_bytes.decode(encoding, 'replace')
解码每个文件,并将结果(以utf8编码)写入另一个文件。通过result.count(u'\ufffd')
计算错误。使用您用于确定gb18030解码结果的任何内容查看输出文件。 U+FFFD字符应显示为黑色钻石内的白色问号。
如果您决定可以丢弃不可解码的部分,则最简单的方法是raw_bytes.decode(encoding, 'ignore')
进一步信息后更新
所有这些\\
都令人困惑。似乎“获取字节”涉及repr(repr(bytes))
而不是只有repr(bytes)
...在交互式提示符下,执行bytes
(您将获得一个隐式的repr()),或print repr(bytes)
(它不会获得隐式的repr())
空格:我假设您的意思是'\xf8\xf8'.decode('gb18030')
被您解释为某种全角空格,并且解释是通过使用某个无法命名的查看器软件进行视觉检查完成的。是这样吗?
实际上,'\xf8\xf8'.decode('gb18030')
-> u'\e28b'
。U+E28B位于Unicode PUA(专用区域)中。 “空格”可能意味着查看器软件在使用的字体中不会有U+E28B的字形。
也许文件的来源故意使用PUA来表示标准gb18030中不存在的字符、注释或传输伪秘密信息。如果是这样,您将需要使用解码tambourine,这是最近俄罗斯研究的一个分支,详情请参见
此处报告。
另一种方法是cp939-HKSCS理论。根据香港政府的说法,HKSCS big5代码FE57曾经映射到U+E28B,但现在映射到U+28804。
关于“欧元符号”:您说:“由于数据我不能分享整行,但我称之为欧元符号的字符是:\xcb\xbe\x80\x80”[我假设
\
被省略了,而
"
是字面意思]。当“欧元符号”出现时,总是在我不需要的同一列中,所以我希望只使用“忽略”。不幸的是,由于“欧元符号”紧挨着文件中的引号,有时“忽略”会同时去除欧元符号和引号,这对csv模块确定列造成问题。
如果您能展示这些
\x80
字节与引号和中文字符的关系模式,将会极大地帮助我们。请保持可读性,仅显示十六进制,并使用C1 C2来代表“我确定表示一个中文字符的两个字节”。例如:
C1 C2 C1 C2 cb be 80 80 22
请提供以下两种情况的示例:(1) 在使用“replace”或“ignore”时,“"”未丢失;(2) 引号丢失的情况。在您迄今为止的唯一示例中,“"”未丢失:
>>> '\xcb\xbe\x80\x80\x22'.decode('gb18030', 'ignore')
u'\u53f8"'
而且,发送一些调试代码的提议(请参见下面的示例输出)仍然有效。
>>> import decode_debug as de
>>> def logger(s):
... sys.stderr.write('*** ' + s + '\n')
...
>>> import sys
>>> de.decode_debug('\xcb\xbe\x80\x80\x22', 'gb18030', 'replace', logger)
*** input[2:5] ('\x80\x80"') doesn't start with a plausible code sequence
*** input[3:5] ('\x80"') doesn't start with a plausible code sequence
u'\u53f8\ufffd\ufffd"'
>>> de.decode_debug('\xcb\xbe\x80\x80\x22', 'gb18030', 'ignore', logger)
*** input[2:5] ('\x80\x80"') doesn't start with a plausible code sequence
*** input[3:5] ('\x80"') doesn't start with a plausible code sequence
u'\u53f8"'
>>>
Eureka: -- 有时会丢失引号的可能原因 --
似乎在 gb18030
解码器的替换/忽略机制中存在一个 bug: \x80
不是有效的 gb18030 前导字节;当检测到它时,解码器应该尝试与下一个字节重新同步。然而,它似乎忽略了 \x80
和随后的字节:
>>> '\x80abcd'.decode('gb18030', 'replace')
u'\ufffdbcd'
>>> de.decode_debug('\x80abcd', 'gb18030', 'replace', logger)
*** input[0:4] ('\x80abc') doesn't start with a plausible code sequence
u'\ufffdabcd'
>>> '\x80\x80abcd'.decode('gb18030', 'replace')
u'\ufffdabcd' # the second '\x80' is lost
>>> de.decode_debug('\x80\x80abcd', 'gb18030', 'replace', logger)
*** input[0:4] ('\x80\x80ab') doesn't start with a plausible code sequence
*** input[1:5] ('\x80abc') doesn't start with a plausible code sequence
u'\ufffd\ufffdabcd'
>>>