Windows 10家庭中文版,Python 3.6.4,

下午复习了一下time模块,熟悉一下其中的各种时间格式的转换:时间戳浮点数、struct_tm、字符串,还算顺利。

可是,测试其中的time.tzname属性时遇到了乱码,如下:

 >>> import time
>>> time.tzname
('Öйú±ê׼ʱ¼ä', 'ÖйúÏÄÁîʱ')

返回了一个元组,可是,乱码怎么看得懂!

补充:time.tzname

A tuple of two strings: the first is the name of the local non-DST timezone, the second is the name of the local DST timezone.

从结果来看,返回的是两个Unicode字符串组成的元组。

那么,这两个字符串用的是什么编码呢?怎么转换为孤可以读的懂得信息呢?

网上搜索到一篇文章(https://www.oschina.net/question/2927993_2199064?sort=default),解决方法为:

 a = time.tzname[0]
b = a.encode('latin-1').decode('gbk')
print(b)

说明,后面的gbk更改为gb2312也是可以的。

测试的b:

中国标准时间

上面代码解释(参考链接1中会解释的更清楚):

使用encode将字符串转换为bytes,再使用decode将bytes转换为字符串,最后得到一个gbk编码的字符串,此字符串在Python IDLE就可以正常显示了。

能看懂了。可是,为什么要做这样的转换呢?为何是latin-1、gbk呢?继续dig

补充:

除了使用encode、decode实现str、bytes转换外,还可以使用str()、bytes()来执行两者的转换,下面会用到。

补充:

str.encode(encoding="utf-8", errors="strict")
Return an encoded version of the string as a bytes object. Default encoding is 'utf-8'. bytes.decode(encoding="utf-8", errors="strict")
bytearray.decode(encoding="utf-8", errors="strict")
Return a string decoded from the given bytes. Default encoding is 'utf-8'.

疑问:怎么判断字符串用的什么编码方式呢?

字符串,可以认为是字符组成的数组,那么,获取每个字符串中的字符在内存中的表示如何?是什么样的整数?当然,Python中是没有单纯的字符的,都是字符串。

在参考链接2中,找到了 将字符转换为整数的函数——ord:

下面是使用

>>> tzname = time.tzname
>>> for ch in tzname[0]:
print("0x%x" % ord(ch)) 0xd6
0xd0
0xb9
0xfa
0xb1
0xea
0xd7
0xbc
0xca
0xb1
0xbc
0xe4

遗憾的是,由于自己水平有限,无法根据上面的信息使用的是何种编码方式。

下面是更进一步测试

item = time.tzname[0]

Test 1:

bsx0 = bytes(item, encoding="gbk")

发生异常:

UnicodeEncodeError: 'gbk' codec can't encode character '\xd6' in position 0: illegal multibyte sequence

看来上面的做法是不对的。上面的bytes()函数类似于encode的功能——字符串str 转 bytes。

Test 2:

bs0 = bytes(item, encoding="utf-8")
print(bs0)
print(chardet.detect(bs0))
print("OK 1? ", str(bs0, 'utf-8'))
print('0x%x' % ord(str(bs0, 'utf-8')[0]))

测试结果:

b'\xc3\x96\xc3\x90\xc2\xb9\xc3\xba\xc2\xb1\xc3\xaa\xc3\x97\xc2\xbc\xc3\x8a\xc2\xb1\xc2\xbc\xc3\xa4'
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''} 使用chardet.detect检测到的编码类型
OK 1? Öйú±ê׼ʱ¼ä 还是乱码,和IDLE中一样
0xd6 先执行bytes、再执行str,两次都用utf-8,结果,得到的第一个字符的十六进制仍然是0Xd6

Test 3:

bs = bytes(item, encoding="latin-1")
print(bs)
print(chardet.detect(bs))
str_bs = str(bs, 'gbk')
print(str_bs)
print('0x%x' % ord(str_bs[0]))

print(bytes(str_bs, encoding='gbk'))

测试结果:

b'\xd6\xd0\xb9\xfa\xb1\xea\xd7\xbc\xca\xb1\xbc\xe4' 字符串转bytes时使用了latin-1,得到的编码,和打印每个字符的16进制的结果一致
{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'} 可是,使用chardet.detect检测到的编码居然是GB2312
中国标准时间 bytes使用gbk(gb2312也可以)转换为str后输出的结果,好了,不是乱码了
0x4e2d 查看上面的字符串的第一个字符的十六进制数值,这次不一样了,

b'\xd6\xd0\xb9\xfa\xb1\xea\xd7\xbc\xca\xb1\xbc\xe4' 使用gbk编码得到的bytes,和前面使用latin-1编码得到的bytes一样啊!

Test 4:

继续上面的Test 3进行测试:str_bs是上面使用gbk转换后得到的字符串

bs2 = bytes(str_bs, encoding='utf-8')
print(bs2)
print(chardet.detect(bs2))
print("OK 2? ", str(bs2, 'utf-8'))
print('0x%x' % ord(str(bs2, 'utf-8')[0]))

测试结果:

b'\xe4\xb8\xad\xe5\x9b\xbd\xe6\xa0\x87\xe5\x87\x86\xe6\x97\xb6\xe9\x97\xb4' 将编码为gbk字符串用utf-8转换为bytes,结果和Test 3中得到的不一样,
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''} 检测到编码为utf-8,
OK 2? 中国标准时间 也显示了看得懂的字符串
0x4e2d 第一个字符的十六进制,

疑问

问题在哪儿呢?为何孤要将字符串转换为UTF-8呢?

Unicode字符编码、UTF-8、GBK、GB2312到底有什么关系呢?

b'\xd6\xd0\xb9\xfa\xb1\xea\xd7\xbc\xca\xb1\xbc\xe4'

怎么转换为:

b'\xe4\xb8\xad\xe5\x9b\xbd\xe6\xa0\x87\xe5\x87\x86\xe6\x97\xb6\xe9\x97\xb4'

计算方法是什么?

Test 5:

new_item = item.encode('latin-1').decode('gbk')
print('OK 3?', new_item)
print('0x%x' % ord(new_item[0]))

new_item2 = new_item.encode('gbk').decode('utf8')
print(new_item2)

测试结果:

OK 3? 中国标准时间
0x4e2d
Traceback (most recent call last):
File "D:\eclipse\workspace\zl0425\src\test\aug\time01.py", line 52, in <module>
new_item2 = new_item.encode('gbk').decode('utf8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd6 in position 0: invalid continuation byte 出错了!

疑惑:

在Test 3中,原始字符串 使用latin-1转换为bytes 再使用gbk转化为字符串;

在Test 4中,将Test 3得到的gbk转化来的字符串使用utf-8转换为bytes 再用utf-8转换为字符串;

latin-1 --> gbk -->utf-8,没有出错,可在Test 5中使用encode、decode时出错了呢?

将出错语句中的gbk更改为utf8,结果,new_item2中显示正常了:

new_item2 = new_item.encode('utf8').decode('utf8')

结果:

中国标准时间

1723 还是不完全明白,晚点再看看

1805 开机,电量满满的,再战此问题

看过参考链接4、5,并对汉字“汉”做了一些实验,发现,无论是 encode还是decode,都是对内存中的字节进行操作。

下面是使用bytes()、str()函数进行测试的结果:

# 本身就是Unicode字符
>>> han = '汉'
# 输出 汉 在Unicode字符集中的 编码
>>> ord(han)
27721
>>> print('0x%x' % ord(han))
0x6c49 # 使用latin-1将Unicode字符——大于255——转换为bytes:异常,无法解析
# Unicode字符小于256时是可以的!
>>> bytes(han, encoding='latin-1')
Traceback (most recent call last):
File "<pyshell#63>", line 1, in <module>
bytes(han, encoding='latin-1')
UnicodeEncodeError: 'latin-1' codec can't encode character '\u6c49' in position 0: ordinal not in range(256) # Unicode字符 使用 utf-8转换为bytes,成功
# 用什么解码,就用什么进行编码
>>> hanbs = bytes(han, encoding='utf-8')
# 三个字节的UTF-8编码
>>> hanbs
b'\xe6\xb1\x89' # 将UTF-8编码得到的字节使用latin-1编码转换为字符串
# 是按照上面的每个直接进行处理,结果得到一个长度为3的字符串,存在看不懂的乱码
# \xe6、\xb1、\x89分别代表一个字符
# 此时是Unicode字符,但小于256
>>> han_latin = str(hanbs, 'latin-1')
>>> han_latin
'æ±\x89' # 将latin-1编码的字符串使用utf-8转换为bytes
# 每个字符一个转换,三个字符就是三个转换
# 结果得到下面的bytes——utf-8编码的bytes,此时有6个字节了
# 每两个字节代表一个 前面han_latin中的一个字符(Unicode字符)
>>> hanbs2 = bytes(han_latin, encoding='utf-8')
>>> hanbs2
b'\xc3\xa6\xc2\xb1\xc2\x89'
>>> str(hanbs2, encoding='utf-8')
'æ±\x89' # 还是用latin-1编码将latin-1编码的字符串转换为bytes吧
# 在把bytes转换为utf-8编码的字符串,又恢复了“汉”
>>> hanbs3 = bytes(han_latin, encoding='latin-1')
>>> hanbs3
b'\xe6\xb1\x89'
>>> str(hanbs3, encoding='utf-8')
'汉' # 对字母a进行测试
>>> zimu = 'a'
>>> ord(zimu)
97
>>> print('0x%x' % ord(zimu))
0x61 >>> zimubs = bytes(zimu, encoding='utf-8')
>>> zimubs
b'a'
>>> zimu_latin = str(zimubs, 'latin-1')
>>> zimu_latin
'a' # 无论如何转换,得到的bytes都是b'a',
# 因为latin-1、utf-8编码对小于256的是兼容的——相同
>>> bytes(zimu_latin, 'utf-8')
b'a'

上面的测试做完后,发现自己对用不同编码方式进行 编码、解码 的原理是了解了。

那么,为何在编解码中会发生错误呢?

存储在内存中的字节数组的 不符合相应 的 编码方式 的编码规则,比如,超过其范围了,这样的话,异常就发生了。

不只是bytes()、str()函数会报错,encode()、decode()函数也会报错。其实,两套函数的功能是相同的(需要试验证明)。

好了,不用为字符集编码什么的发愁了,再次面对时,将充满自信,嘿~

参考链接:

1.Python中的str与bytes

2.python中的字符数字之间的转换函数

3.Python | 多种编码文件(中文)乱码问题解决

4.编码方式的简介(ASCII, LATIN-1, UTF-8/16/32)

5.ISO-8859-1 、Latin-1 西欧编码介绍及应用

0830 0954-更新参考链接:

6.网页编码就是那点事

7.Java| 编码格式介绍(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)

8.彻底搞懂字符编码(unicode,mbcs,utf-8,utf-16,utf-32,big endian,little endian...)

9.windows内码、外码、字符映射表

10.UTF-8和UTF-16使用对比

总结:

阅读完更新的链接后,发现不同字符集编码的字符之间的转换的成本是很高的,,比如,Unicode中的汉字 转换为 GB18030中的汉字,需要查找它们各自码表的对应值,或许有人在做这个工作,或许没有人做。

GB2312原来在1981年5月就开始实施了啊!真早!中国国家标准总局 制定的。

之后,GBK包含GB2312,之后,GB18030包含GBK,GB18030-2005包含G18030-2000,,之后没有更多更新了。

之后就是万国码Unicode了!最新版本Unicode 11.0:2018年6月5日(来自百度百科 Unicode 词条)!

Unicode和GB*字符集是不兼容的,转换成本很高,或许有现成软件,也可能没有。

至于UTF-8,是Unicode字符集的 网络传输编码方式。问题,为何要用UTF-8呢?根据参考链接10的介绍,有两个原因:

1.传输效率,可以节约传输的流量——变长设计

2.避免网络传输时字节破坏的问题

至于UTF-16,Java在内存里面使用其编码,但网络传输时,使用UTF-8。

Ok,就到这里。

由time.tzname返回值引发的对str、bytes转换时编码问题实践的更多相关文章

  1. 由JS函数返回值引发的一场”血案"

    ---恢复内容开始--- 啊...  本来昨天晚上想写来着,结果陪老婆看电视剧就忘了... 呢滴神啊,原谅我吧. 背景:昨天在项目中做一个小功能的时候,出现了个小问题,而且一开始找了半天也没找到原因. ...

  2. JAVA函数的返回值类型详解以及生成随机数的例题

    函数的四要素:函数名.输入.输出(返回).加工. 函数分为两种:一种是有返回值得函数,一种是没有返回值的函数. 1. 定义:没有返回值的函数:(当我不需要函数的计算结果再拿出来进行运算的时候,我就不需 ...

  3. Android - 和其他APP交互 - 获得activity的返回值

    启用另一个activity不一定是单向的.也可以启用另一个activity并且获得返回值.要获得返回值的话,调用startActivityForResult()(而不是startActivity()) ...

  4. ajax请求后台,有时收不到返回值的解决办法

    昨天下午做项目遇到一个问题,贴出来方便以后翻阅,也给大家个参考. 问题: 具体做的是个文件导入的功能,导入的功能是成功了,但是界面一直得不到返回值,排查了一下午,调试的时候是可以有返回的,但是关掉浏览 ...

  5. C# 多线程编程,传参,接受返回值

    C# 多线程编程,传参,接受返回值 今天将多线程的知识有回顾了下,总结了几点: 新建一个线程(无参数,无返回值) Thread th = new Thread(new ThreadStart(Prin ...

  6. [日常] Go语言圣经-函数多返回值习题

    Go语言圣经-函数多返回值1.在Go中,一个函数可以返回多个值2.许多标准库中的函数返回2个值,一个是期望得到的返回值,另一个是函数出错时的错误信息3.如果一个函数将所有的返回值都显示的变量名,那么该 ...

  7. MyBatis中Mapper的返回值类型

    insert.update.delete语句的返回值类型 对数据库执行修改操作时,数据库会返回受影响的行数. 在MyBatis(使用版本3.4.6,早期版本不支持)中insert.update.del ...

  8. 使用泛型集合取代datatable作为返回值实现面向对象

    开会的时候,师父说.我们在机房重构时,尽量不要用datatable作为返回值.改用泛型集合的方式,这样能够实现真正的面向对象. 通过查资料和同学交流,把这个问题给攻克了. 对于泛型集合.我也有了一些认 ...

  9. 关于用python作为第三方程序,来调用shell命令的问题,以及返回值格式解析

    1.用python语言作为第三方,调用shell 在python2.x中,可以通过包commands来进行调用shell命令.如下: cmd就是你要调用的shell命令,把环境配置好,输入正确的命令格 ...

随机推荐

  1. [转帖]Edge投降Chromium!微软王牌浏览器是如何跪倒的

    Edge投降Chromium!微软王牌浏览器是如何跪倒的   https://tech.sina.com.cn/n/k/2018-12-17/doc-ihmutuec9824604.shtml   谷 ...

  2. 2017全球GDP总量达74万亿美元 各国占比排行榜

    全球GDP总量达74万亿美元 各国占比排行榜     2017年公布的2015年全球各国GDP占比,数据图片来源:世界银行报告 2月24日,来自世界银行的最新GDP数字已于2月早些时候公布,现由How ...

  3. [转帖] Linux 下面栈空间大小的实验

    比如局部变量是保存在栈空间中的,今天突然在想栈的上限是多大呢,什么时候才会栈溢出? ulimit 命令 linux下使用ulimit 命令可以查看系统的很多上限值. ulimit -a 查看所有 ul ...

  4. TP5 关联模型使用(嵌套关联、动态排序以及隐藏字段)

    在数据库设计中,常常会有如下这种关联模型,分类表中一条分类对应多个商品表中的商品 如果要获得分类表中每条分类 以及 对应的商品的信息,则需要先查询分类表中的数据,然后根据结果遍历查询商品表,最后把数据 ...

  5. Java多线程与线程同步

    六.多线程,线程,同步 ①概念: 并行:指两个或多个在时间同一时刻发生(同时发生) 并发:指两个或多个事件在同一时间段内发生 具体概念: 在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多 ...

  6. Django_ KindEditor 插件使用

    KindEditor  富文本编辑器插件 目的及原理: 更便捷的在前端页面上实现用户的文本编辑操作, 本质上就是对标签的样式进行封装和事件预处理, 常规操作都可以通过直接的引入即可实现, 但是对于存在 ...

  7. 内置函数enumerate()

    enumerate是枚举的意思,顾名思义,enumerate()函数用来将一个可迭代序列生成一个enumerate对象,该enumerate对象的每个元素是由可迭代对象的索引编号和对应的元素组成的元祖 ...

  8. java绘图合并图像AlphaComposite模式测试

    package com.hdwang.test; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.sw ...

  9. .net网站iis应用池完美解决方案

    一.防DDOS攻击11条: 1.确保所有服务器采用最新系统,并打上安全补丁.计算机紧急响应协调中心发现,几乎每个受到DDoS攻击的系统都没有及时打上补丁. 2.确保管理员对所有主机进行检查,而不仅针对 ...

  10. 浅谈移动端 View 的显示过程

    作者:个推安卓开发工程师 一七 随着科技的发展,各种移动端早已成为人们日常生活中不可或缺的部分,人们使用移动端产品工作.社交.娱乐……移动端界面的流畅性已经成为影响用户体验的重要因素之一.那么你是否思 ...