关于python2和3中字符编码的问题
公司买了一个继电器控制器,通过与上位机建立socket TCP连接,可以发送相关指令进行控制,但是开发资料给的是python2的代码,我想移植到python3中,里面就遇到了一系列的环境的问题,解决过程异常曲折。
源码如下:
1 | import socket |
其中 data_on
和data_off
是开断指令,RTU格式,以16进制发送。程序先将指令每两位取出,转成十进制,通过chr()
函数找到对应码值的ASCII字符,最后拼接,建立socket连接,发送。
一开始我将代码直接放到python3的环境中运行,但是继电器没有任何变化。于是我开始比较,我发现在windows环境下, 发现chr(1)
的结果竟然是不一样的!(这里是失误,和命令行环境有关系,真是惊天bug!后面会讲)
python3:
python2:
通过资料了解到,python2用的字符集默认是ASCII,而3用的是Unicode,因此在python2中如果有汉字的字符集,会出现报错,需要手动指明coding
。于是我开始各种ASCII和Unicode编码之间转换,但是我觉得奇怪的是,Unicode是ASCII的一种扩容才对,那么至少在标准ASCII (0-127)和扩展ASCII (128-255) 字符应该是一致的才对,但是为什么chr(1)
输出的结果会不正确?
而且在python2中, chr(1)
和unichr(1)
,打印在命令行的字符串由是一样的!
也就是说,同样是Unicode编码,但是python2和python3的打印结果不一致!!!
但是我没有细想这个问题,而是在编码的问题上渐行渐远。尝试了各种办法转码,最终以失败告终。
后来我发现,在python的字符里是可以用16进制表示的,而例程中将指令转来转去的目的也无非是获得对应的字符,继电器在通过收到的字符转成16进制,对寄存器进行相关操作。于是我将代码修改如下:
1 | import socket |
python2中正常,但是python3直接运行报错:
TypeError: a bytes-like object is required, not 'str'
这是由于,scoket 发送的数据发生了变化:
python3 要求指令是bytes类型,而不能是字符串。注意这里不是string转bytes,而是这条指令就是bytes, string转bytes需要指定编码,最后得到的不是我们想要的指令。于是,python3的程序为:
1 | import socket |
其实传送指令就应该是bytes类型,之所以python2可以发送字符串,是因为:
Python 2 将字符串处理为 bytes 类型。
Python 3 将字符串处理为 unicode 类型。
而最开始chr(1)出现笑脸的字符串,是因为我在cmder命令行中执行出现的乱码结果!!!
换个cmd工具就没问题了:
参考资料
https://docs.python.org/2/library/socket.html
socket — Low-level networking interface — Python 3.8.2 documentation
https://stackoverflow.com/a/21233499
python3 字符集编码以及python3 乱码问题_Python_热心市民王先生-CSDN博客
python 字符串string 开头r b u f 含义 str bytes 转换 format_Python_心之所向-CSDN博客