如何将Java的byte[]转换为Python的字符串?

5
我知道Java和Python在处理字节时有所不同,因此我有些困惑如何将byte[]转换为Python字符串。我有一个Java中的byte[]。
{ 118, -86, -46, -63, 100, -69, -30, -102, -82, -44, -40, 92, 0, 98, 36, -94 }

我想将其转换为Python字符串,以下是我的处理方法:

b=[118, -86, -46, -63, 100, -69, -30, -102, -82, -44, -40, 92, 0, 98, 36, -94]
str=""
for i in b:
    str=str+chr(abs(i))

但是我不确定这是否是正确的做法。


1
byte是Java中的数据类型,它不对应于Python的bytestrings。尽管您可以从中获得结果,但它很可能是没有意义的。 - Eli Sadoff
3
如果这些字节以二进制补码存储,那么使用abs()函数会破坏信息。 - fafl
请参考"在Python中将整数转换为字符串?",了解将单个Python int转换为str的最小示例。 - Kevin J. Chase
当你输入b=[118, ...]时,你已经将它转换为Python了。你真正的问题可能更像是“如何将Python列表转换为字符串?”或者“如何将许多Python整数转换为字符串?”。第一个可能是str(b)repr(b);第二个则类似于' '.join(str(x) for x in b)。另请参阅str.join文档。 - Kevin J. Chase
3个回答

4
Java中的byte类型是一个有符号整数,其值范围在-128到127之间。Python的chr函数期望的值范围是0到255。来自Java教程的原始数据类型部分

byte:byte数据类型是8位有符号二进制补码整数。它的最小值为-128,最大值为127(含)。

您需要将2s补码转换为无符号整数:
def twoscomplement_to_unsigned(i):
    return i % 256

result = ''.join([chr(twoscomplement_to_unsigned(i)) for i in b])

然而,如果这是 Python 3,您确实希望使用 bytes 类型:

result = bytes(map(twoscomplement_to_unsigned, b))

1
可以在Python中实现为i%256 - anthony sottile
Martijn,我注意到你在连接时在括号内使用了一个列表。这样做比直接将gencomp传递给join更快吗? - Jean-François Fabre
@Jean-FrançoisFabre:参见 Python中不带“[ ]”的列表推导式;对于*str.join()*函数,将列表作为参数传递可以提高速度。 - Martijn Pieters
我已经遇到过这个问题,所以才问的。不再“少用符号,多用字母”了。很多人会建议去掉它们,但是join还是会创建列表,只是速度比较慢而已。顺便说一句,"".join(map(chr, items))也会有同样的性能问题吧?现在这个map函数真的真的没什么用处了。 - Jean-François Fabre
@Jean-FrançoisFabre:是的,map() 在这里也有同样的问题。 - Martijn Pieters

2

字符串拼接效率非常低。

我建议使用生成器表达式传递给str.join方法并使用空分隔符进行字符串拼接:

s = "".join([chr(abs(x)) for x in b])

编辑:这里的“abs”有些奇怪。它会按照要求执行操作,但由于“byte”是带符号的,所以没有什么用处。因此,您需要使用Martijn答案中的二进制补码来解决下一个问题:数据有效性 :)
如果您有一些ASCII值的列表(放在表格中),那就没问题了(去掉“abs”可以让我们使用“map”,这样做很少见,让我们不要剥夺这种机会 :)
items = [65, 66, 67, 68]
print("".join(map(chr,items)))

结果:

"ABCD"

使用map(lambda x: chr(abs(x)), b)可能会更有效率吗? - Eli Sadoff
我认为它是等价的。但正如你所说,传递负字节的绝对值是不推荐的。 - Jean-François Fabre
@MartijnPieters 是的,它没有任何有用的功能。 - Jean-François Fabre
我明白了笑话!抱歉,我只是复制了原帖有缺陷的代码。已修复。 - Jean-François Fabre
@Jean-FrançoisFabre,你以为我是认真的吗?抱歉,我只是开玩笑 :) 我只是想提醒你。 - Christian Dean
不用道歉,我喜欢开玩笑,而且我懂你的意思!但事实就在这里:代码有缺陷,所以谢谢你指出来。我不想在那个网站上留下有缺陷的东西(最近删除了两个得分为+3的答案。虽然很痛苦,但这就是生活)。 - Jean-François Fabre

2
假设你正在使用Python 3,那么bytes类型已经可以从列表中初始化。但是你需要先将有符号整数转换为无符号字节。
items = [118, -86, -46, -63, 100, -69, -30, -102, -82, -44, -40, 92, 0, 98, 36, -94]
data = bytes(b % 256 for b in items)
print(data)  # b'v\xaa\xd2\xc1d\xbb\xe2\x9a\xae\xd4\xd8\\\x00b$\xa2'

如果字节表示的是文本,请在之后对其进行解码。在您的示例中,它们不代表编码为UTF-8的文本,因此这将失败。
data = data.decode('utf8')
print(data)

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