Python中的汉字编码错误

2024-09-26 22:52:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我是一个初学者,在Python2.7中很难将几十个包含数字+简体中文字符的CSV文件解码为UTF-8。

我不知道输入文件的编码,所以我已经尝试了所有可能的编码——GB18030、UTF-7、UTF-8、UTF-16和UTF-32(LE&BE)。另外,为了更好地测量,GBK和GB3212,尽管它们应该是gb8030的子集。UTF中的所有字符在到达第一个汉字时都会停止。除GB18030外,其他编码在第一行的某个地方停止。我认为这是解决办法,因为它能读懂前几个文件,并能很好地解码它们。我的代码的一部分,逐行阅读,是:

line = line.decode("GB18030")

我试图解码的前两个文件运行良好。在第三个文件的中途,Python抛出

UnicodeDecodeError: 'gb18030' codec can't decode bytes in position 168-169: illegal multibyte sequence

在这个文件中,大约一百万行中有5个这样的错误。

我在文本编辑器中打开输入文件,检查哪些字符给出了解码错误,前几个字符在CSV文件的特定列中都有欧元符号。我很有信心这些都是错别字,所以我想删除欧元字符。我想逐一检查编码错误的类型;我想去掉所有的欧元错误,但不想忽略其他错误,直到我首先看到它们。

编辑:我使用了chardet,它将GB2312作为所有文件的.99置信度编码。我试着用GB2312解码得到:

UnicodeDecodeError: 'gb2312' codec can't decode bytes in position 108-109: illegal multibyte sequence

Tags: 文件csvin编码bytes错误line解码
3条回答

“。。。GB18030。我想这是个解决办法,因为它能通读前几个文件,并能很好地解码。”“”——请解释一下你的意思。对我来说,成功解码有两个标准:第一,原始字节。解码(“某些编码”)没有失败,第二,在特定语言中显示的结果unicode有意义。当用latin1iso_8859_1解码时,宇宙中的每个文件都将通过第一个测试。东亚语言中的许多文件都通过了第一个gb18030测试,因为汉语、日语和朝鲜语中最常用的字符大多使用相同的两字节序列块进行编码。你第二次考试做了多少?

不要纠结于在IDE或文本编辑器中查看数据。在web浏览器中查看它;它们通常能更好地检测编码。

你怎么知道这是一个欧元字符?通过查看文本编辑器的屏幕,该编辑器使用什么编码来解码原始字节?cp1252?

你怎么知道里面有汉字?你确定不是日本人吗?韩国人?你从哪儿弄来的?

香港、台湾、澳门、大陆等地方的中文文件使用{{CD4>}或^ {CD5>}编码——试试看。

在任何情况下,接受马克的建议并指出chardetchardet如果文件足够大并且正确编码了中文/日文/韩文,通常可以很好地检测所使用的编码—但是如果有人使用单字节字符集在文本编辑器中手动编辑文件,则一些非法字符可能会导致其他99.9%字符未检测到的编码。

您可能想对文件中的5行执行print repr(line),并将输出编辑为您的问题。

如果该文件不是机密文件,您可以将其提供给下载。

文件是在Windows上创建的吗?你是怎么用Python阅读的?(显示代码)

评论后更新:

记事本等不试图猜测编码;“ANSI”是默认值。你得告诉它该怎么做。您所称的欧元字符是编辑器使用您的环境的默认编码解码的原始字节“\x80”——通常怀疑是“cp1252”。不要用这样的编辑器来编辑你的文件。

早些时候你说的是“最初的几个错误”。现在你说你总共有5个错误。请解释一下。

如果该文件确实几乎是正确的gb18030,您应该能够逐行解码该文件,当您得到这样一个错误时,捕获它,打印错误消息,从消息中提取字节偏移量,打印repr(两个坏字节),然后继续。我对\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中的字符,或者用于注释,或者用于传输伪机密信息。如果是这样的话,你就需要求助于解码手鼓,这是最近俄罗斯研究的一个分支。

备选方案:cp939香港特别行政区理论。根据香港政府的资料,香港特别行政区第五大类密码FE57曾映射到U+E28B,但现在已映射到U+28804。

“euro”:你说“”,因为我不能共享整行数据,但我所说的euro字符是在:“\xcb\xbe\x80\x80”[我假设从一开始就省略了\,而"是字面的]。当“欧元字符”出现时,它总是在我不需要的同一列中,所以我希望只使用“忽略”。不幸的是,由于“euro char”就在文件中的引号旁边,有时“ignore”会去掉euro字符和引号,这给csv模块确定列带来了问题

如果你能显示这些\x80字节相对于引号和汉字出现的位置的模式,那将有很大的帮助——通过显示十六进制保持可读,并隐藏机密数据,例如,使用C1 C2表示“两个字节,我确信这两个字节代表一个汉字”。例如:

C1 C2 C1 C2 cb be 80 80 22 # `\x22` is the quote character

请提供以下示例:(1)“未被‘替换’丢失”或“忽略”(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解码器替换/忽略机制中有一个错误:\x80不是有效的gb18030前置字节;当检测到它时,解码器应尝试与下一个字节重新同步。然而,它似乎忽略了\x80和以下字节:

>>> '\x80abcd'.decode('gb18030', 'replace')
u'\ufffdbcd' # the 'a' is lost
>>> 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'
>>>

你可以试试chardet

试试这个:

codecs.open(file, encoding='gb18030', errors='replace')

不要忘记参数errors,您还可以将其设置为'ignore'

相关问题 更多 >

    热门问题