簡體   English   中英

二進制數據被寫入字符串文字 - 如何將其轉換回字節?

[英]Binary data gets written as string literal - how to convert it back to bytes?

我正在將壓縮數據作為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'"

問題是,是否可以將其轉換回字節類型以便我可以解壓縮它? 如果是這樣,如何?

我已經看到了一些不同的例子(例如, 如何將字符串強制轉換為字節而不進行編碼)對於我正在嘗試的內容並不完全有效。

更新:

很多好的答案,謝謝大家! 我希望我可以點擊其中的多個接受。 是的,正如你們許多人所指出的,它是 zlib 壓縮的。 這是設計使然,因為我們的工作空間極其有限,如果可能的話,我們希望繼續使用 JSON(隨意選擇 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')

正在發生的事情是這樣的:

黑盒服務器在發送之前對字節進行字符串化。 您需要獲取代表字節的字符串並將其轉換回字節。 最簡單的方法是使用抽象語法樹庫 (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 ,你可以看到它是一個拉鏈

所以,我使用 zlib 庫來解碼它......整潔的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM