将一个整数值转换为Unicode。

34

我正在使用pyserial,并且需要发送一些小于255的值。如果我发送整数本身,则会发送整数的ASCII值。因此,现在我将整数转换为Unicode值,并通过串行端口发送它。

unichr(num_less_than_255);

然而它引发了这个异常:

'ascii' codec can't encode character u'\x9a' in position 24: ordinal not in range(128)

如何将整数转换为Unicode的最佳方法?


Python2还是Python3?(猜测是Python2,但这很重要)你确定unichr是导致崩溃的调用吗?你是如何实际发送unichr返回的数据的? - Joachim Isaksson
3
unichr() 在 Python 3 中不存在,因此这是 Python 2。在 Python 3 中,unichr() 被命名为 chr()(用于将字符转换为 Unicode 字符)。 - Eric O. Lebigot
4个回答

33
在Python 2中 - 首先将它转换为字符串,然后再转换为Unicode。
str(integer).decode("utf-8")

我认为这是最好的方式。适用于任何整数,而且如果您将字符串作为输入放入其中,它仍然有效。

由于评论而更新的编辑:对于Python 2和3-这适用于两者,但有点凌乱:

str(integer).encode("utf-8").decode("utf-8") 

5
str(integer).encode("utf-8").decode("utf-8") 这行代码虽然不太美观,但在 Python 2 和 3 上都能正常工作。而上面的代码只适用于 Python 2。 - Ivan X

24

只需使用chr(somenumber)即可获取一个整数的1个字节值,只要它小于256。 pySerial将能够顺利地发送它。

如果您要通过pySerial发送数据,最好查看标准库中的struct模块。它处理了大小端问题和打包问题,以及编码几乎每种您可能需要的1个或多个字节的数据类型。


如果某个回答对您有用并且您将其标记为已接受,那么也公平地给它点赞。欢迎来到StackOverflow! - Eric O. Lebigot
3
还没有代表权,必须努力争取 :-) - user2578666
@user2578666:我明白了,我忘记了这个规则。祝你声誉迅速提升。 :) - Eric O. Lebigot
chr(32) 返回的是空格,其他数字都正常工作。如何克服值为32的问题? - Venu
7
chr(32) 也等同于十六进制的空格字符 0x20 - 你希望看到什么? - Steve Barnes

12

我认为最好的解决方案是明确表示你要将一个数字表示为一个字节(而不是作为字符):

>>> import struct
>>> struct.pack('B', 128)
>>> '\x80'

这使得你的代码可以在Python 2和Python 3中运行(在Python 3中,结果应该是bytes对象)。在Python 3中,另一种选择是使用新的bytes([128])来创建一个值为128的单个字节。
我不太喜欢使用chr()的解决方案: 在Python 3中, 它们会产生一个(字符,而不是字节)字符串,需要在发送到任何地方(文件、套接字、终端等)之前进行编码——Python 3中的chr()相当于问题中有问题的Python 2的unichr()。使用struct的解决方案具有正确生成字节的优点,无论Python的版本如何。如果您想使用chr()通过串行端口发送数据,则需要控制随后进行的编码。当Python 3使用的默认编码为UTF-8时(我认为是这种情况),代码可能会工作,但这是因为小于256的代码点的Unicode字符可以在UTF-8中编码为单个字节。这增加了一层不必要的微妙和复杂性,我不建议这样做(它使代码更难理解,并且如果需要,更难调试)。
因此,我强烈建议您使用上述方法(也由Steve Barnes和Martijn Pieters暗示):它清楚地表明您希望生成一个字节(而不是字符)。即使在使用Python 3运行代码时,它也不会给您任何惊喜,并且可以使您的意图更清晰和明显。

1
Bravo @EOL - C++ 继承了 C 语言中的许多误导性问题之一(可能还有其他很多)——在长度为1的字符串、单个字符(本地编码下的文本)和字节之间没有任何区别。 - Steve Barnes

10
请使用 chr() 函数,您正在发送一个小于256但大于128的值,但是却创建了一个Unicode字符。
然后必须先对Unicode字符进行编码才能获得一个字节字符,由于您使用的值超出了ASCII范围(0-127),因此该编码失败。
>>> str(unichr(169))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa9' in position 0: ordinal not in range(128)

这是正常的Python 2行为;当尝试将Unicode字符串转换为字节字符串时,必须进行隐式编码,而默认编码为ASCII。

如果您改用chr(),则会创建一个字符的字节字符串,不需要进行隐式编码:

>>> str(chr(169))
'\xa9'

你可能想要了解的另一种方法是 struct 模块,特别是当你需要发送大于255的整数值时:

>>> struct.pack('!H', 1000)
'\x03\xe8'

以上示例将一个整数按照网络字节顺序打包成无符号短整型。


@EOL: 这是Python 2,这是一个字符串对象,它实际上是一个字节序列。但在循环中遍历它会得到长度为1的字符串;即字节字符。 - Martijn Pieters
不要将其与“print”语句/函数编码为“sys.stdout”的编解码混淆。 - Martijn Pieters
您提供的参考文献是关于unicode()函数的,而不是关于Unicode字符串如何默认编码的。您说的是ASCII编码,我理解使用的编码是sys.getdefaultencoding()。也许我误解了文档,但我仍然找不到更明确的说明。 - Eric O. Lebigot
但是你可以在Python提示符中尝试我的示例。sys.getdefaultencoding()是用于编码“print”输出的编解码器。Unicode和字符串之间的隐式转换使用“ASCII”。 - Martijn Pieters
我准备相信你关于这两点。 :) 但是这在文档中吗? - Eric O. Lebigot
显示剩余9条评论

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