二进制数据以字符串文字形式写入如何将其转换回字节?

2024-10-02 04:17:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在将压缩数据作为bytes类型写入黑盒API(即,我无法更改引擎盖下发生的事情)。当我返回数据时,它将作为string类型返回,我无法使用通用python模块(zlib、bz2等)对其进行解压缩

更详细地说,部分问题在于该字符串包含前导'b',例如
b'x\x9c\xabV*HL\xd1\xcd\xccK\xcbW\xb2RPJ\xcb\xcfOJ,R\xaa\x05\x00T\x83\x07b'
(这是一种字符串类型)

当我将其与原始的二进制表示进行比较时,除了引号和前导B之外,它是相同的

如果我尝试简单地转换回字节(例如,使用bytes函数),它会包装整个内容并转义斜杠,我得到如下结果:

b"b'x\\x9c\\xabV*HL\\xd1\\xcd\\xccK\\xcbW\\xb2RPJ\\xcb\\xcfOJ,R\\xaa\\x05\\x00T\\x83\\x07b'"

问题是,是否可以将其转换回字节类型,以便我可以解压缩它?如果是,怎么做

我已经看到了一些不同的例子(例如,How to cast a string to bytes without encoding),它们对我正在尝试的东西不太适用

更新:

很多好答案,谢谢大家!我希望我能点击多个按钮。是的,正如你们很多人所注意到的,它是zlib压缩的。这是出于设计考虑的,因为我们的工作空间非常有限,如果可能的话,我们希望继续使用JSON(zlib是任意选择的,只是为了解决二进制数据的问题,可能不是最终的选择)


Tags: 数据字符串类型stringbyteshlzlib前导
3条回答

发生的情况是:

黑盒服务器正在发送字节之前对字节进行字符串化。您需要获取表示字节的字符串并将其转换回字节。最简单的方法是使用抽象语法树库(ast)

import ast
import zlib

stringified_bytes = "b'x\\x9c\\xabV*HL\\xd1\\xcd\\xccK\\xcbW\\xb2RPJ\\xcb\\xcfOJ,R\\xaa\\x05\\x00T\\x83\\x07b'"
print(f"{type(stringified_bytes)}: {stringified_bytes}")

actual_bytes = ast.literal_eval(stringified_bytes)
print(f"{type(actual_bytes)}: {actual_bytes}")

answer = zlib.decompress(actual_bytes)
print(f"Answer: {answer}")

下面是脚本的运行:

(venv) [ttucker@zim stackoverflow]$ python bin.py 
<class 'str'>: b'x\x9c\xabV*HL\xd1\xcd\xccK\xcbW\xb2RPJ\xcb\xcfOJ,R\xaa\x05\x00T\x83\x07b'
<class 'bytes'>: b'x\x9c\xabV*HL\xd1\xcd\xccK\xcbW\xb2RPJ\xcb\xcfOJ,R\xaa\x05\x00T\x83\x07b'
Answer: b'{"pad-info": "foobar"}'

。。。这是非常有趣的东西。。。看起来他们还有一个包含JSON的字节字符串。这是黑客编码的挑战之一吗

顺便说一下,你有一个zlib文件

我知道这一点,因为数据的开头两个字节是78 9cx=78十六进制)。。。如果你看这里:https://en.wikipedia.org/wiki/List_of_file_signatures,你可以看到它是一个zlip

所以,我用zlib库来解码它。。。干净的东西

假设原始字符串的类型为str,则具有以下原始字符串(文字长度为4个转义码,而不是表示1字节的实际转义码):

s = r"b'x\x9c\xabV*HL\xd1\xcd\xccK\xcbW\xb2RPJ\xcb\xcfOJ,R\xaa\x05\x00T\x83\x07b'"

如果删除前导的b'',则可以使用latin1编码转换为字节latin1是Unicode代码点到字节值的1:1映射,因为前256个Unicode代码点表示latin1字符集:

>>> s[2:-1].encode('latin1')
b'x\\x9c\\xabV*HL\\xd1\\xcd\\xccK\\xcbW\\xb2RPJ\\xcb\\xcfOJ,R\\xaa\\x05\\x00T\\x83\\x07b'

这现在是一个字节字符串,但包含文字转义码。现在应用unicode_escape编码将实际代码点转换回str

>>> s2 = b.decode('unicode_escape')
>>> s2
'x\x9c«V*HLÑÍÌKËW²RPJËÏOJ,Rª\x05\x00T\x83\x07b'

这现在是一个Unicode字符串,带有代码点,但我们仍然需要一个字节字符串。再次使用latin1编码:

>>> b2 = s2.encode('latin1')
>>> b2
b'x\x9c\xabV*HL\xd1\xcd\xccK\xcbW\xb2RPJ\xcb\xcfOJ,R\xaa\x05\x00T\x83\x07b'

一步:

>>> s = r"b'x\x9c\xabV*HL\xd1\xcd\xccK\xcbW\xb2RPJ\xcb\xcfOJ,R\xaa\x05\x00T\x83\x07b'"
>>> b = s[2:-1].encode('latin1').decode('unicode_escape').encode('latin1')
>>> b
b'x\x9c\xabV*HL\xd1\xcd\xccK\xcbW\xb2RPJ\xcb\xcfOJ,R\xaa\x05\x00T\x83\x07b'

此示例数据似乎是一个zlib压缩的JSON字符串:

>>> import zlib,json
>>> json.loads(zlib.decompress(b))
{'pad-info': 'foobar'}

通过选择除前两个b'和最后一个'字符之外的整个字符串,可以从字符串中提取字节。然后首先将其转换为字节,然后解码回字符串

这里有一个例子:

str(bytes(bytes_string[2:-1], encoding), encoding)

其中:

bytes_string = "b'x\x9c\xabV*HL\xd1\xcd\xccK\xcbW\xb2RPJ\xcb\xcfOJ,R\xaa\x05\x00T\x83\x07b'"

编码是字节字符串中使用的编码(例如“UTF-8”)

相关问题 更多 >

    热门问题