UnicodeEncodeError: 'latin-1'编解码器无法对字符进行编码。

119
尝试将外语字符插入数据库时出现错误,可能是什么原因引起的?
>>UnicodeEncodeError: 'latin-1' codec can't encode character u'\u201c' in position 0: ordinal not in range(256)

我该如何解决这个问题?谢谢!

46
db = MySQLdb.connect(host="localhost", user = "root", passwd = "", db = "testdb", use_unicode=True, charset="utf8")这行代码用于连接一个名为"testdb"的MySQL数据库,使用用户名"root"和空密码,其字符集为"utf8",并启用Unicode编码。 - KyungHoon Kim
12个回答

101

在使用Python MySQLdb模块时,我遇到了同样的问题。由于MySQL会允许您将几乎任何二进制数据存储在文本字段中,而不考虑字符集,所以我在这里找到了解决方案:

使用UTF8与Python MySQLdb

编辑:引用上面网址中的内容以满足第一条评论中的请求...

"UnicodeEncodeError:'latin-1'编解码器无法对字符进行编码..."

这是因为MySQLdb通常尝试将所有东西编码为Latin-1。可以通过在建立连接后立即执行以下命令来解决此问题:

db.set_character_set('utf8')
dbc.execute('SET NAMES utf8;')
dbc.execute('SET CHARACTER SET utf8;')
dbc.execute('SET character_set_connection=utf8;')

"db"是MySQLdb.connect()的结果,而"dbc"是db.cursor()的结果。


1
建议在答案中提供链接项的相关部分。额外阅读的链接很好,但请尽量在您的答案中加入执行摘要,以便说 :) - Fluffeh
1
非常感谢,经过尝试了一千种方式之后终于成功了。 - Juergen Riemer
2
只有db.set_character_set('utf8')才能解决这个问题。 - Pandurang Patil

81

字符 U+201C 左双引号在 Latin-1 (ISO-8859-1) 编码中不存在。

它存在于代码页 1252 (西欧语言) 中。这是一种基于 ISO-8859-1 的 Windows 特有编码,将额外的字符放入范围 0x80-0x9F 内。代码页 1252 经常被误认为是 ISO-8859-1,并且现在已成为标准 Web 浏览器行为的一种令人烦恼的问题:如果您将页面呈现为 ISO-8859-1,则浏览器将把它们视为 cp1252。但是,它们实际上是两种不同的编码:

>>> u'He said \u201CHello\u201D'.encode('iso-8859-1')
UnicodeEncodeError
>>> u'He said \u201CHello\u201D'.encode('cp1252')
'He said \x93Hello\x94'

如果你的数据库仅用于字节存储,你可以使用cp1252进行编码以转义和其他出现在Windows西方代码页中的字符。但是,其他未出现在cp1252中的Unicode字符将会导致错误。

你可以通过使用encode(..., 'ignore')来抑制错误并丢弃这些字符,但实际上,在本世纪中,你应该在数据库和页面中都使用UTF-8编码。这种编码允许使用任何字符。最理想的情况是,你应该告诉MySQL你正在使用UTF-8字符串(通过设置数据库连接和字符串列的排序规则),这样它就可以正确地进行大小写不敏感的比较和排序。


1
cp1252不是ISO-8859-1的严格超集吗?也就是说,当浏览器接收到一个ISO-8859-1页面时,它们可以将其呈现为CP1252,因为页面中不会有来自范围0x80-0x9F的任何字符。 - MSalters
3
不,ISO-8859-1确实为字节0x80-0x9F分配了真实的值,但它们被cp1252的添加覆盖,因此它不是超集。它们恰好映射到Unicode字符U+0080-U+009F,这些字符是一些控制字符的选择。它们是不经常使用的控制字符,这就是为什么浏览器可以得以通过,但在试图将字节序列转换为Unicode时,这很烦人。 - bobince
我曾经看到过在以ISO-8859-1或UTF-8编码的文件中出现U+0080-U+009F范围内的字符,这是由于某些小丑将一堆文件连接在一起,其中一些文件是以cp850编码的,然后将结果混乱的文件从"latin1"转换为UTF-8。草案HTML5规范正在考虑认可这种非常实用的浏览器行为(以及许多类似情况)--请参见http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#character-encodings-0。 - John Machin

24

最佳解决方案是:

  1. 将mysql的字符集设置为“utf-8”
  2. 按照以下注释操作(添加use_unicode=Truecharset="utf8"

    db = MySQLdb.connect(host="localhost", user = "root", passwd = "", db = "testdb", use_unicode=True, charset="utf8") – KyungHoon Kim Mar 13 '14 at 17:04

详见:

class Connection(_mysql.connection):

    """MySQL Database Connection Object"""

    default_cursor = cursors.Cursor

    def __init__(self, *args, **kwargs):
        """

        Create a connection to the database. It is strongly recommended
        that you only use keyword parameters. Consult the MySQL C API
        documentation for more information.

        host
          string, host to connect

        user
          string, user to connect as

        passwd
          string, password to use

        db
          string, database to use

        port
          integer, TCP/IP port to connect to

        unix_socket
          string, location of unix_socket to use

        conv
          conversion dictionary, see MySQLdb.converters

        connect_timeout
          number of seconds to wait before the connection attempt
          fails.

        compress
          if set, compression is enabled

        named_pipe
          if set, a named pipe is used to connect (Windows only)

        init_command
          command which is run once the connection is created

        read_default_file
          file from which default client values are read

        read_default_group
          configuration group to use from the default file

        cursorclass
          class object, used to create cursors (keyword only)

        use_unicode
          If True, text-like columns are returned as unicode objects
          using the connection's character set.  Otherwise, text-like
          columns are returned as strings.  columns are returned as
          normal strings. Unicode objects will always be encoded to
          the connection's character set regardless of this setting.

        charset
          If supplied, the connection character set will be changed
          to this character set (MySQL-4.1 and newer). This implies
          use_unicode=True.

        sql_mode
          If supplied, the session SQL mode will be changed to this
          setting (MySQL-4.1 and newer). For more details and legal
          values, see the MySQL documentation.

        client_flag
          integer, flags to use or 0
          (see MySQL docs or constants/CLIENTS.py)

        ssl
          dictionary or mapping, contains SSL connection parameters;
          see the MySQL documentation for more details
          (mysql_ssl_set()).  If this is set, and the client does not
          support SSL, NotSupportedError will be raised.

        local_infile
          integer, non-zero enables LOAD LOCAL INFILE; zero disables

        autocommit
          If False (default), autocommit is disabled.
          If True, autocommit is enabled.
          If None, autocommit isn't set and server default is used.

        There are a number of undocumented, non-standard methods. See the
        documentation for the MySQL C API for some hints on what they do.

        """

2
这个答案需要更多的赞。这是一个干净的解决方案,清除了应用层不必要的编码开销。 - yeaske
太好了!这正是我在寻找的。 - Geek
此外,如果在 MySQL 中使用了表情符号等内容,最好将字符集设置为 utf8mb4。请参考 what-is-the-difference-between-utf8mb4-and-utf8-charsets-in-mysql - Cheney

21

我希望你的数据库至少是UTF-8编码。在将字符串放入数据库之前,你需要运行yourstring.encode('utf-8')


5
使用以下代码片段将文本从拉丁语转换为英语。
import unicodedata
def strip_accents(text):
    return "".join(char for char in
                   unicodedata.normalize('NFKD', text)
                   if unicodedata.category(char) != 'Mn')

strip_accents('áéíñóúü')

输出:

'aeinouu'


也许在这种情况下,更详细地解释为什么这个方法(NFKD规范化)有效会更有描述性。 - Farhan Hai Khan

4
你正在尝试使用编码ISO-8859-1 / Latin-1存储Unicode代码点\u201c,但该编码无法描述该代码点。你可能需要更改数据库使用utf-8,并使用适当的编码存储字符串数据,或者在存储内容之前对输入进行清理;例如使用像Sam Ruby的出色i18n指南这样的东西。它讨论了windows-1252可能引起的问题,并建议如何处理它,以及链接到示例代码!

3

SQLAlchemy的用户只需要将字段指定为convert_unicode=True

例子: sqlalchemy.String(1000, convert_unicode=True)

SQLAlchemy会直接接受Unicode对象并处理编码,然后再返回它们。

文档


1

Latin-1(又称ISO 8859-1)是一种单字节字符编码方案,而你无法将\u201c)放入一个字节中。

你是否意味着使用UTF-8编码?


1
Latin-1编码了_特定的_Unicode字符,只是不包括那个。如果\u201c不能放入一个字节中也无所谓。Windows-1252也是一种单字节编码方案,并且包括\u201c。 - Mark Tolonen
cp1253(也称为windows-1253)是一种单字节字符编码方案,但\u0391可以在一个字节(具体来说是字节193)中很好地适配。你可能想看一下这个;人们发现它很有帮助。 - tzot
Unicode将Latin-1/cp1253字形作为16位代码点合并在一起。我很惊讶评论似乎声称相反的情况。 - msw
@msw 您误解了并做出了错误的声明。即使在2010年,Unicode也不是16位的。评论谈论了覆盖拉丁-1字符集之外一些特定Unicode码点的8位编码。这些编码仍然是8位的,就像拉丁-1一样,但包含不同的“扩展”字符(我讨厌这个术语,但在这个上下文中希望清晰)。 - tripleee

1
UnicodeEncodeError: 'latin-1'编解码器无法在位置106处编码字符'\u2013',因为该位置的序数不在范围内(256)。
解决方案1: \u2013-谷歌搜索字符含义,以确定实际导致此错误的字符。然后,您可以使用编码中的其他某个字符替换字符串中的特定字符。
解决方案2: 将字符串编码更改为包含字符串中所有字符的某种编码。然后,您可以打印该字符串,它将正常工作。
下面的代码用于更改字符串的编码,借鉴自@bobince
 u'He said \u201CHello\u201D'.encode('cp1252')

0

mysql.connector 的最新版本只有

db.set_charset_collation('utf8', 'utf8_general_ci')

而不是

db.set_character_set('utf8') //This feature is not available

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