UnicodeDecodeError: 'utf8'编解码器无法在第12个位置解码0x9a字节。

3
我正在使用chatterbot库开发一个聊天机器人。这个聊天机器人将使用我的母语——斯洛文尼亚语,其中包含许多奇怪的字符(例如:š,č,ž)。我在使用Python 2.7。

当我尝试训练机器人时,该库对上述字符存在困难。例如,当我运行以下代码时:

chatBot.set_trainer(ListTrainer)
chatBot.train([
            "Koliko imam še dopusta?",
            "Letos imate še 19 dni dopusta.",
        ])

它抛出以下错误:

UnicodeDecodeError: 'utf8'编解码器无法在位置12解码字节0x9a:无效的起始字节

我在文件顶部添加了# -*- coding: utf-8 -*-行,我还通过我的编辑器(Sublime text 3)将所有使用的文件编码更改为utf-8,我使用以下代码更改了系统默认编码:

import sys
reload(sys)
sys.setdefaultencoding('utf8')

字符串的类型是unicode。
当我尝试使用这些奇怪的字符获取响应时,它工作正常,没有问题。例如,在与上述训练代码相同的执行中运行以下代码(当我在训练字符串中将's'更改为'š'和'c'更改为'č'时),不会引发错误:
chatBot.set_trainer(ListTrainer)
chatBot.train([
            "Koliko imam se dopusta?",
            "Letos imate se 19 dni dopusta.",
        ])    
chatBot.get_response("Koliko imam še dopusta?")

我无法找到解决此问题的方法。有什么建议吗? 非常感谢您的帮助。 :) 编辑:我使用了from __future__ import unicode_literals,使字符串成为unicode类型。我还检查了它们是否真的是unicode类型,使用了type(myString)方法。 我还想粘贴这个link。 编辑2:@MallikarjunaraoKosuri - s代码可以工作,但在我的情况下,我还有一个东西在聊天机器人实例初始化中,如下所示:
chatBot = ChatBot(
    'Test',
    trainer='chatterbot.trainers.ListTrainer',
    storage_adapter='chatterbot.storage.JsonFileStorageAdapter'
)

这是我的错误原因。聊天机器人创建的json存储文件是使用本地编码创建的,而不是utf-8。似乎默认的存储(.sqlite3)没有这个问题,所以现在我只会避免使用json存储。但我仍然有兴趣找到解决这个错误的方法。

你说字符串是unicode类型的:你是否使用了 from __future__ import unicode_literals?另外,哪一行引发了解码错误?因为如果字符串是unicode类型的,它们就不应该被解码(它们已经全部解码了),所以也不应该有任何解码错误。 - lenz
不要更改默认编码。setdefaultencoding 被禁用是有原因的(库期望默认为 ascii)。 - Mark Tolonen
1
#coding 声明了源文件的编码方式。请确保你实际上将源文件保存在声明的编码方式下。 - Mark Tolonen
@lenz 是的,我正在使用 from __future__ import unicode_literals。解码错误是在 train("Koliko imam še dopusta?", "Letos imate še 19 dni dopusta.") 方法内引发的。 - matiOS
@MarkTolonen,好的,我会从我的代码中删除它。我在其他一些stackoverflow答案中看到过类似问题的解决方法,并且在那个线程中被标记为正确的答案。我认为它保存为utf-8格式,我是用Sublime完成的,正如下面的答案所建议的那样。这就是我所说的“我还通过我的编辑器(Sublime text 3)更改了所有使用文件的编码为utf-8”。但是,我怎么知道在这样做之后,我的文件实际上是以utf-8编码的呢?当我保存时,程序底部会显示一个状态,指示文件保存的位置,然后在括号中显示utf-8。 - matiOS
“reload”技巧通常由新手推荐,并被其他新手标记为正确。但这并不意味着它是正确的。以下是一篇关于此的文章:why-sys-setdefaultencoding-will-break-code - Mark Tolonen
2个回答

0

你的示例中的字符串不是unicode类型。

否则,Python就不会抛出UnicodeDecodeError错误。
这种类型的错误表示,在程序执行的某个步骤中,Python尝试将字节串解码为unicode,但由于某种原因失败了。

在你的情况下,原因是:

  • 解码配置为utf-8
  • 你的源文件不是utf-8,几乎肯定是cp1252
  • import unicodedata
    
    b = '\x9a'
    
    # u = b.decode('utf-8') # UnicodeDecodeError: 'utf8' codec can't decode byte 0x9a 
                            # in position 0: invalid start byte
    
    u = b.decode('cp1252')
    
    print unicodedata.name(u) # LATIN SMALL LETTER S WITH CARON
    print u # š
    

    所以,来自你的cp1252源的0x9a字节无法使用utf-8进行解码。


    最好的解决方案是除了将您的源代码转换为utf-8之外,什么都不做。
    使用Sublime Text 3,您可以轻松地执行此操作:文件 -> 使用编码重新打开 -> UTF-8
    但在转换之前不要忘记Ctrl+C您的源代码,因为在转换后,所有的š, č, ž字符都将被替换为?


    我已经尝试过这个了,这就是我所说的:“我还通过我的编辑器(Sublime Text 3)更改了所有使用文件的编码为UTF-8”。但我会再试一下,感觉可能有些方向上的问题。它是Unicode类型,或者至少是type(myString)方法告诉我的。 - matiOS
    我将提到的字符串"Koliko imam še dopusta?"保存在变量myString中,然后运行了type(myString)代码,结果是unicode。不过我明白你想告诉我的,看起来答案就在这个方向上。我按照你建议的方式准确地更改了编码。 - matiOS
    你说得没错,但在我的情况下,我还包括了以下内容:from __future__ import unicode_literals,这将导致结果为<type 'unicode'>。我知道我应该在最初的问题中添加这个,后来进行了编辑,可能是在你看到帖子之后。我尝试了一下,结果是: >>> view.encoding() 'UTF-8' - matiOS
    1
    @matiOS,我重新创建了你的示例 - 使用相同的文件内容,在顶部添加了 # coding: utf-8from __future__ import unicode_literals。如果源代码是 cp1252 格式,则会抛出 SyntaxError: (unicode error) 'utf8' codec can't decode byte 0x9a ... 错误。如果我将源代码转换为 utf-8 格式,则一切正常。 - MaximTitarenko
    我找到问题了!! :) 我的代码没有问题,源文件编码也正确,除了聊天机器人存储其数据的JSON数据库。我不知道如何更改库创建文件的编码,所以我想我只会在初始化新的聊天机器人实例时不使用 storage_adapter="chatterbot.storage.JsonFileStorageAdapter",而是使用默认的 .sqlite3 存储。你指出了正确的方向。 - matiOS
    显示剩余2条评论

    0

    我们的一些朋友已经提出了一些好的部分解决方案,但我想把所有的解决方案结合起来。

    作者@gunthercox建议在这里描述了一些指南http://chatterbot.readthedocs.io/en/stable/encoding.html#how-do-i-fix-python-encoding-errors

    # -*- coding: utf-8 -*-
    from chatterbot import ChatBot
    
    # Create a new chat bot named Test
    chatBot = ChatBot(
        'Test',
        trainer='chatterbot.trainers.ListTrainer'
    )
    
    chatBot.train([
        "Koliko imam še dopusta?",
        "Letos imate še 19 dni dopusta.",
    ])
    

    Python 终端

    >>> # -*- coding: utf-8 -*-
    ... from chatterbot import ChatBot
    >>> 
    >>> # Create a new chat bot named Test
    ... chatBot = ChatBot(
    ...     'Test',
    ...     trainer='chatterbot.trainers.ListTrainer'
    ... )
    >>> 
    >>> chatBot.train([
    ...     "Koliko imam še dopusta?",
    ...     "Letos imate še 19 dni dopusta.",
    ... ])
    List Trainer: [####################] 100%
    >>> 
    

    你说得对,运行上述代码对我也有效。但是这段代码和我的原始代码之间有一个小差别。在初始化聊天机器人实例时,我使用了以下行:storage_adapter="chatterbot.storage.JsonFileStorageAdapter",它会以本地编码而不是utf-8写入到指定的数据库中。有什么建议可以解决这个问题吗?我将编辑我的原始问题,提供新学到的信息。 - matiOS
    它将从生产中移除,https://github.com/gunthercox/ChatterBot/issues/473#issuecomment-265726313。我建议您使用默认存储适配器“sqlite3”。 - Mallikarjunarao Kosuri

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接