Python 2.7 + SQLite3 编码问题 gaunthan Posted on Dec 31 2016 ? Pyhton 2.7 ? ? SQLite3 ? ? Coding ? ## Problem Report 今天在使用Python 2.7 + SQLite3的时候遇到了一个问题: > sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings. ## Summary 引发该问题的是下面代码中的插入语句: ```Python # -*- coding: UTF-8 -*- # create_db.py # ... # 连接 conn = sqlite3.connect('./mydb.db') c = conn.cursor() # ... # 格式:月份,蒸发量,降水量 c.execute('''CREATE TABLE weather (month text, evaporation text, precipitation text)''') # 插入数据 c.execute('INSERT INTO weather VALUES (?,?,?)', ('六月', 76.7, 70.7)) # ... ``` ## Why? 我将'六月'换成了ASCII串后,问题解决了。将其转化为其他非ASCII字符,同样会报上面提到的错误。 这样看来本问题是发生在编码、解码方式的不统一之上的。简单点说就是**编码问题**。百度一波Python编码问题,相信您打人的心都有了。 注意,有些造成该问题的原因是Python和SQLite类型转换不统一造成的。如果您发现本教程没有解决你的问题,可以转入附录,查看下您的系统中的转换情况。 ## Solving 解决方法参考了一篇博文:[如何在sqlite3中插入中文字符 ](https://my.oschina.net/letiantian/blog/217770)。 按照问题中的描述,解决方法有两种: - 将数据库连接的text_factory属性设置为str ```Python conn.text_factory = str ``` - 将插入的数据转换为unicode ```Python # 一般该句会是这样的:str = str.decode('utf-8') str = str.decode('xxx') # 将要插入的数据按照xxx编码解码为unicode ``` ### About Coding 在我的系统中,使用方法一成功解决了问题。 然而, 使用方法二却报了另一个错误: > UnicodeDecodeError: 'utf8' codec can't decode byte 0xc1 in position 0: invalid start byte 这似乎表明:代码中的中文字符串恐怕不是utf-8编码的(怎么会!我都使用了`#coding: utf-8`了:))让我们实验一波看看:  在字符串前面加前缀`u`,解释器就会用unicode表示它(使用**UCS-2**)。对其使用`encode.('utf-8')`可以编码为utf-8。而对一串utf-8可以使用`decode.('utf-8')`解码为UCS-2表示。 现在让我们试试不加前缀`u`:  不加前缀'u'的情况下,s不是用unicode编码的。考虑到代码来自我的老师(中国人),估计是用GBK编码的。我们试试用`decode('gbk')`看看:  解码成功!看来这些字符串是使用GBK编码的。这意味着我的问题还可以这样解决: ```Python month = '六月'.decode('gbk') # 按照GBK编码,解码为unicode。这样插入到数据库中的就是unicode串 month = u'六月' # 这样也可以 c.execute('INSERT INTO weather VALUES (?,?,?)', (month, 76.7, 70.7)) ``` 使用查询语句读到的数据如下: [(u'\u516d\u6708', u'76.7', u'70.7')] 那如果我要批量插入呢?比如: ```Plain # 数据# 格式:月份,蒸发量,降水量 purchases = [('1月', 2, 2.6), ('2月', 4.9, 5.9), ('3月', 7, 9) ] ``` 每一个中文字符串我都要这样搞,那岂不是累死?这时候就得设置好你的输入环境了,要么更改系统配置,要么更改编辑器配置,将GB2312编码的文件转换为UTF-8格式。比如,可以使用Sublime的`Set File Encoding to`功能:  事实上···这只是把文件的编码设置更改了,内容还是没有更改。因此你还得使用一款编码转换工具。然而Sublime也给你提供了这个功能:`Save with Encoding`功能。或者你也可以先创建一个UTF-8编码的文件,然后复制粘贴代码过去,编辑器会自动转换的。 我用Sublime提供的'Reopen with coding`功能,发现原文件是GB2312编码的:  难怪各种错误。因此我不仅要将文件的编码更改为UTF-8,还得把给这些中文字符串加上前缀`u`,或者把它们按照GBK2312解码。 ## Appendix ### Type Convertion bewteen Python & SQLite  图片来自[官方说明文档](https://docs.python.org/2/library/sqlite3.html#module-sqlite3)。 ### References - [python 中文乱码问题深入分析](http://www.jb51.net/article/26543.htm) - [python编码错误:UnicodeDecodeError: 'utf8' codec can't decode](http://blog.sina.com.cn/s/blog_940224600101499e.html) - [如何在sqlite3中插入中文字符](https://my.oschina.net/letiantian/blog/217770) 赏 Wechat Pay Alipay 希尔排序(Shell sort) SQLite 简明教程