字符、字符集、编码,以及它们python中会遇到的一些问题(下)
在看了很多的博客文章之后,总结整理得到了以下文章,非常感谢这些无私奉献的博主!
文章末尾有本文引用的文章的链接,如果有漏掉的文章引用,可以发邮件联系我,随后再次附上链接!
侵删!!!
这一部分是下篇,主要讲的是编码部分,以及在python中会遇到的一些编码问题,偏向于实际应用一点。
上篇介绍了字符、字符集的一些概念,以及他们在python中的一些简单的代码示例,偏向于概念。
上篇地址:http://www.cnblogs.com/echo-coding/p/7435118.html
这绝对是个源远流长的大坑,对于新手来说恶心致死(尤其是windows)...........
二、decode、encode(python编码)
上面介绍了字符、字符集和字符编码,为这一小结做了准备。
一些重要概念:
系统编码:默认编码,正常情况下window系统默认是gbk,Linux系统默认是utf-8,可用locale.getdefaultlocale()和locale.setdefaultlocale()来控制,与encode有关
用python自带的locale模块来检测命令行的默认编码(也就是系统的编码)和设置命令行编码:
- import locale
- #get coding type
- print locale.getdefaultlocale()
- ('zh_CN', 'cp936')
- #set coding type
- locale.setlocale(locale.LC_ALL, locale='zh_CN.GB2312')
- print locale.getlocale()
- ('zh_CN', 'gb2312')
表明当前系统的内部编码是cp936,近似于GBK。实际上中文XP和WIN7的系统内部编码都是cp936(GBK)。
tips:linux系统下系统默认编码为utf8编码,window默认编码为gbk编码
python编码:指python内设置的解码方式。如果不设定的话,python默认的是ascii解码方式。如果python源代码文件中不出现中文的话,这个地方怎么设定应该不会问题。
- #查看python编码
- import sys
- sys.getdefaultencoding()
- #结果
- 'ascii'
- #更改python编码
- sys.setdefaultencoding('utf-8')
永久地将python默认采用的编码设置为utf-8:在python的Lib\site-packages文件夹下新建一个sitecustomize.py,内容为:
- # encoding=utf8
- import sys
- reload(sys)
- sys.setdefaultencoding('utf8')
此时重启python解释器,执行sys.getdefaultencoding(),发现编码已经被设置为utf8的了,多次重启之后,效果相同,这是因为系统在python启动的时候,自行调用该文件,设置系统的默认编码,而不需要每次都手动的加上解决代码,属于一劳永逸的解决方法。
文件编码:文本的编码方式,sys.getfilesystemencoding()
读写文件:
内置的open()方法打开文件时,read()读取的是str,读取后需要使用正确的编码格式进行decode()(变成unicode)。write()写入时,如果参数是unicode,则需要使用你希望写入的编码进行encode(),如果是其他编码格式的str,则需要先用该str的编码进行decode(), 转成unicode后再使用写入的编码进行encode()。如果直接将unicode作为参数传入write()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入。
- # coding: UTF-8
- f = open('test.txt')
- s = f.read()
- f.close()
- print type(s) # <type 'str'>
- # 已知是GBK编码,解码成unicode
- u = s.decode('GBK')
- f = open('test.txt', 'w')
- # 编码成UTF-8编码的str
- s = u.encode('UTF-8')
- f.write(s)
- f.close()
另外,模块codecs提供了一个open()方法,可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述操作。相对内置的open()来说,这个方法比较不容易在编码上出现问题。使用codecs直接开unicode通道。
- # coding: GBK
- import codecs
- f = codecs.open('test.txt', encoding='UTF-8')
- u = f.read()
- f.close()
- print type(u) # <type 'unicode'>
- f = codecs.open('test.txt', 'a', encoding='UTF-8')
- # 写入unicode
- f.write(u)
- # 写入str,自动进行解码编码操作
- # GBK编码的str
- s = '汉'
- print repr(s) # '\xba\xba'
- # 这里会先将GBK编码的str解码为unicode再编码为UTF-8写入
- f.write(s)
- f.close()
python代码中的编码(代码编码):
1、python代码中的字符串在未被指定编码的情况下,默认编码与代码文件本身的编码一致。举个例子:str = '中文'这个字符串,如果是在utf8编码的代码文件中,该字符串就是utf8编码;如果是在gb2312的文件中,该字符串就是gb2312编码。那么代码文件本身的编码怎么知道呢?
(1)自己指定代码文件的编码:在代码文件的头部加上"#-*- coding:utf-8 -*-"来声明该代码文件为utf-8编码。此时未被指定编码的字符串的编码都变成了utf-8。
顶部的:# -*- coding: utf-8 -*-目前看来有三个作用。
1、如果代码中有中文注释,就需要此声明(否则代码报错,无法解析)
2、比较高级的编辑器(比如我的emacs),会根据头部声明,将此作为代码文件的格式。
3、程序会通过头部声明,解码初始化 u"人生苦短",这样的unicode对象,(所以头部声明和代码的存储格式要一致)
(2)在没有指定代码文件的编码时,创建代码文件时使用的是python默认采用的编码(一般来说是ascii码,在windows中实际保存为cp936(GBK)编码)。通过sys.getdefaultencoding()和sys.setdefaultencoding('...')来获取和设置该默认编码。
终端输入输出编码:sys.stdin.encoding,sys.stdout.encoding,必须与locale编码保持一致,才能print出正确str。
print会根据sys.stdout.encoding再转一次码。
- sys.stdout.encoding
- 'cp936'
- '严'
- '\xe4\xb8\xa5'
- print u'严'
- 严
- print u'严'.encode('utf-8')
- 涓
- print u'严'.encode('gbk')
- 严
- u'严'.encode('utf-8')
- '\xe4\xb8\xa5'
- u'涓'.encode('gbk')
- '\xe4\xb8'
print打印显示的过程
Python2.7中调用print打印var 变量时,操作系统会对var做一定的字符处理:如果var是str类型的变量,则直接将var变量交付给终端进行显示;如果var变量是unicode类型,则操作系统首先将var编码成str类型的对象(编码格式取决于stdout的编码格式),然后再交由终端进行显示。在终端显示时,如果str类型的变量的编码方式和终端设置的编码方式不一致,很可能会出现乱码问题。
还有就是print字符串的时候出现的编码错误问题。原因在于sys.stdout.encoding。print 后面跟的字符串对象的编码类型一定要与sys.stdout.encoding所指定的一致,不一致就会出现编码错误。
console不能正常显示中文,console的编码是由操作系统决定的(windows环境下);
我的操作系统是win8中文版(GBK)
console的编码决定了sys.stdout.encoding的取值,sys.stdout.encoding='cp936'
decode && encode :
decode:解码(从其他方向(utf-8,gbk等.......)到unicode)
- #gbk就是源码的编码方式,解码成了unicode
- '\xa1\xb0'.decode('gbk') #解码
- u'\u201c' #unicode
encode:编码(从unicode到其他方向(utf-8,gbk等.......))
- u'中文'.encode('utf-8')
- '\xe4\xb8\xad\xe6\x96\x87'
简单来说就是,你用的什么规则去编码,你就得用这个规则去解码,否则,要不然就乱码了,要不然就直接报错,没法解啊!!!
但问题就是呢,系统有系统的默认编码格式,你文件明明是utf-8的编码,他偏偏用gbk方式去解码,那要不然就直接解不了,要不然就是牛头不对马嘴呗。
关于打印:
你在打印str的时候,实际就是直接将字节流发送给shell。如果你的字节流编码格式与shell的编码格式不相同,就会乱码。
而你在打印unicode的时候,系统自动将其编码为shell的编码格式,是不会出现乱码的。
其他命令:
文件系统的编码:sys.getfilesystemencoding()
终端的输入编码:sys.stdin.encoding
终端的输出编码:sys.stdout.encoding
一些建议:
1. 使用字符编码声明,并且同一工程中的所有源代码文件使用相同的字符编码声明;
2. 抛弃str,全部使用unicode:按引号前先按一下u,这么做可以减少90%的编码问题;
3. 使用codecs.open()替代内置的open();
4. 绝对需要避免使用的字符编码:MBCS/DBCS和UTF-16;
5、主动设置defaultencoding。(默认的是ascii);
6、代码文件的保存格式要与文件头部的# coding:xxx一致。
其他:
python 3和2很大区别就是python本身改为默认用unicode编码,字符串不再区分"abc"和u"abc", 字符串"abc"默认就是unicode,不再代表本地编码。
python2.7以后不用setdefaultencoding了,这两个(声明头部和setdefaultencoding)是没有区别的
这两个作用不一样:
1. # coding:utf-8 作用是定义源代码的编码。如果没有定义, 此源码中是不可以包含中文字符串的;
2. sys.getdefaultencoding() 是设置默认的string的编码格式。
问题的根源:Python2 中的 string
Python 为了让其语法看上去简洁好用,做了很多 tricky 的事情,混淆 byte string 和 text string 就是其中一例。
在 Python 里,有三大类 string 类型,unicode(text string),str(byte string,二进制数据),basestring,是前两者的父类。
其实,在语言设计领域,一串字节(sequences of bytes)是否应该当做字符串(string)一直是存在争议的。我们熟知的 Java 和 C# 投了反对票,而 Python 则站在了支持者的阵营里。其实我们在很多情况下,给文本做的操作,比如正则匹配、字符替换等,对于字节来说是用不着的。而 Python 认为字节就是字符,所以他们俩的操作集合是一致的。
然后进一步的,Python 会在必要的情况下,尝试对字节做自动类型转换,例如,在上文中的 ==,或者字节和文本拼接时。如果没有一个编码(encoding),两个不同类型之间的转换是无法进行的,于是,Python 需要一个默认编码。在 Python2 诞生的年代,ASCII 是最流行的(可以这么说吧),于是 Python2 选择了 ASCII。然而,众所周知,在需要需要转换的场景,ASCII 都是没用的(128个字符,够什么吃)。
在历经这么多年吐槽后,Python 3 终于学乖了。默认编码是 Unicode,这也就意味着,做所有需要转换的场合,都能正确并成功的转换。
一个非常困惑不解的地方:
打开ipython,一开始就运行:
- import sys
- sys.stdout.encoding
- 'utf-8'
- sys.stdin.encoding
- 'utf-8'
- print '中文'
- 中文
- '中文'
- '\xe4\xb8\xad\xe6\x96\x87'
完事之后,运行一个py(比如tb.py)文件,然后,神奇的事情发生了:
- sys.stdin.encoding
- 'cp936'
- sys.stdout.encoding
- 'cp936'
- print '中文'
- 濂冲+
- '中文'
- '\xe4\xb8\xad\xe6\x96\x87'
至今无解。。。。。。
参考资料和博客:
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
http://blog.chinaunix.net/uid-200142-id-4461708.html
http://www.cnblogs.com/evening/archive/2012/04/19/2457440.html
http://blog.csdn.net/olanlanxiari/article/details/48201231
http://www.jb51.net/article/87739.htm
http://www.cnblogs.com/JohnABC/p/4015504.html
http://www.cnblogs.com/work115/p/5924446.html
https://blog.ernest.me/post/python-setdefaultencoding-unicode-bytes
字符、字符集、编码,以及它们python中会遇到的一些问题(下)的更多相关文章
- 轻松理解python中的闭包和装饰器 (下)
在 上篇 我们讲了python将函数做为返回值和闭包的概念,下面我们继续讲解函数做参数和装饰器,这个功能相当方便实用,可以极大地简化代码,就让我们go on吧! 能接受函数做参数的函数我们称之为高阶函 ...
- python中的向上取整向下取整以及四舍五入的方法
import math #向上取整print "math.ceil---"print "math.ceil(2.3) => ", math.ceil(2. ...
- python中字符编码及unicode和utf-8区别
ascii和unicode是字符集,utf-8是编码集 字符集:为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point) 编码规则:将「码位」转换为字节序列的规则(编码/ ...
- python中Url链接编码处理(urlencode,urldecode)
做完了flask-web应用,这几天想用爬虫做个好玩的电影链接整合器,平时找电影都是在dytt或者dy2018之类的网站,在用dytt搜索电影<美国队长时>,发现他的搜索链接是这样的:ht ...
- python中乱码怎么由来与解决方法
前言曾几何时 Python 中文乱码的问题困扰了我很多很多年,每次出现中文乱码都要去网上搜索答案,虽然解决了当时遇到的问题但下次出现乱码的时候又会懵逼,究其原因还是知其然不知其所以然.现在有的小伙伴为 ...
- SQLServer的排序规则(字符集编码)
SQLServer的排序规则(字符集编码) 一.总结 1.SQLServer中的排序规则就是其他关系型数据库里所说的字符集编码: 2.SQLServer中的排序规则可以在3处设置,如下: 服务器级别( ...
- python中re模块
1.定义 正则表达式是一个特殊的字符序列,能方便的检查一个字符串是否与某种模式匹配.re模块使得python拥有全部的正则表达式功能. 2.用途 通过使用正则表达式,可以:测试字符串内的模式.—— 例 ...
- Python中通过open()操作文件时的文件中文名乱码问题
最近在用Python进行文件操作的时候,遇到创建中文文件名的乱码问题. Python默认是不支持中文的,一般我们在程序的开头加上#-*-coding:utf-8-*-来解决这个问题,但是在我用open ...
- 在Python中使用protobuf2.6.1 string format utf-8 and unicode error
版本信息: protobuf: v2.6.1 python: 2.7 关于在Python中使用protobuf时 string格式字段的编码问题 在python中编码格式多采用utf-8格式.而pro ...
- Python中的输入(input)和输出打印
目录 最简单的打印 打印数字 打印字符 字符串的格式化输出 python中让输出不换行 以下的都是在Python3.X环境下的 使用 input 函数接收用户的输入,返回的是 str 字符串 最简单的 ...
随机推荐
- 关于Java String 类型转换时null的问题
开发中经常遇到从集合类List.Map中取出数据转换为String的问题,这里如果处理不好,经常会遇到空指针异常java.lang.NullPointerException,在此总结一下常用转换为St ...
- JS字符串转换为JSON的四种方法笔记
1.jQuery插件支持的转换方式: 示例: $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符串转换成json对象 2.浏览 ...
- Centos7.2下Nginx配置SSL支持https访问(站点是基于.Net Core2.0开发的WebApi)
准备工作 1.基于nginx部署好的站点(本文站点是基于.Net Core2.0开发的WebApi,有兴趣的同学可以跳http://www.cnblogs.com/GreedyL/p/7422796. ...
- 现在开始学习WPF了,mongodb在整理一下
回忆一下自己学习mongodb的过程 1安装 2增删改查 3数据类型转换 4GridFS 5权限管理--开启权限之前先建立一个超级用户(admin库中),开启权限,用该用户登陆,进入admin数据库( ...
- javaScript手记(01)
--------------------javaScript基础1.嵌入页面的方式 1.行间事件(主要用于事件): <input type="button" name=&qu ...
- HTML5新增属性data-*和js/jquery之间的交互
HTML5新增属性data- data-自定义属性,这种方式的自定义属性解决属性混乱无状态管理的现状 书写实例 <div data-role="page" data-last ...
- 蓝桥杯试题利用数学知识经典解法,1.三个空瓶子换一瓶水;2.猜最后一个字母——猎八哥FLY
本博客为本人原创,转载请在醒目位置表明出处. 1.乐羊羊饮料厂正在举办一次促销优惠活动.乐羊羊C型饮料,凭3个瓶盖可以再换一瓶C型饮料,并且可以一直循环下 去,但不允许赊账.请你计算一下,如果小明不浪 ...
- PHP(函数)
<script> // 获得日 var time = new Date(); var x = time.getDate(); document.write(x+"日," ...
- CCIE-MPLS VPN-实验手册(上卷)
看完了看完了看完了,豪爽豪爽豪爽,一个月了,写得挺棒.总共14个mpls vpn的实验,为留下学习的痕迹,原封不动献出. CCIE实验手册 (路由部分-MPLSVPN基础篇) [CCIE] JUST ...
- JS学习一
js中的变量输出 [使用JS的三种方式] 1. 在HTML标签中,直接内嵌JS(并不提倡使用): <button onclick="alert('你真点啊!')"> ...