簡體   English   中英

<bytes> 逃脫 <str> Python 3

[英]<bytes> to escaped <str> Python 3

目前,我有Python 2.7代碼,可通過套接字連接接收<str>對象。 在所有代碼中,我們都使用<str>對象,比較等。為了轉換為Python 3 ,我發現套接字連接現在返回<bytes>對象,這要求我們將所有文字更改為b'abc'做字面比較,等等,這是一個大量的工作,雖然很明顯為什么這個變化是在Python 3搞得我很好奇,如果有任何簡單的解決方法。

假設我通過套接字連接收到<bytes> b'\\xf2a27' 有沒有簡單的方法可以將這些<bytes>轉換為<str>對象,而在Python 3.6中具有相同的轉義 我自己研究了一些解決方案,但無濟於事。

a = b'\xf2a27'.decode('utf-8', errors='backslashescape')

以上的產率'\\\\xf2a27'len(a) = 7 ,而不是原來len(b'\\xf2a27') = 3 索引編制也是錯誤的,但這根本行不通,但似乎是正確的方法。

a = b'\xf2a27'.decode('latin1')

上面產生了'òa27' ,其中包含我要避免的Unicode字符。 盡管在這種情況下, len(a) = 5a[0] == '\\xf2'有效,但我希望盡可能地保留表示形式中的信息。

也許我缺少一個更優雅的解決方案?

您確實必須考慮收到的數據代表什么,Python 3在該方向上很重要。 實際上代表字節集合的字節字符串和(抽象,Unicode)字符字符串之間存在重要區別。

如果每個數據都有不同的表示形式,則可能需要分別考慮它們。

讓我們把你的例子b'\\xf2a27'這在其原始形式從套接字接收僅僅是一個4個字節的字符串: 0xf20x610x320x37十六進制或242975055十進制。

  1. 假設您實際上想要4個字節。 您可以將其保留為字節字符串,也可以將其轉換為字節list或字節tuple (如果這樣做更好):

     raw_bytes = b'\\xf2a27' list_of_bytes = list(raw_bytes) tuple_of_bytes = tuple(raw_bytes) if raw_bytes == b'\\xf2a27': pass if list_of_bytes == [0xf2, 0x61, 0x32, 0x37]: pass if tuple_of_bytes == (0xf2, 0x61, 0x32, 0x37): pass 
  2. 假設這實際上代表一個32位整數,在這種情況下,您應該將其轉換為Python int 選擇是以小端字節序還是大端字節序編碼,並確保選擇正確的帶符號和無符號。

     raw_bytes = b'\\xf2a27' signed_little_endian, = struct.unpack('<i', raw_bytes) signed_little_endian = int.from_bytes(raw_bytes, byteorder='little', signed=True) unsigned_little_endian, = struct.unpack('<I', raw_bytes) unsigned_little_endian = int.from_bytes(raw_bytes, byteorder='little', signed=False) signed_big_endian, = struct.unpack('>i', raw_bytes) signed_big_endian = int.from_bytes(raw_bytes, byteorder='big', signed=True) unsigned_big_endian, = struct.unpack('>I', raw_bytes) unsigned_big_endian = int.from_bytes(raw_bytes, byteorder='big', signed=False) if signed_litte_endian == 926048754: pass 
  3. 假設它實際上是文本。 考慮一下它的編碼方式。在您的情況下,它不能為UTF-8,因為b'\\xf2'將是無法正確解碼為UTF-8的字節字符串。 如果它是latin1 aka iso8859-1,而且您確定可以,那就很好。

     raw_bytes = b'\\xf2a27' character_string = raw_bytes.decode('iso8859-1') if character_string == '\\xf2a27': pass 

    如果您選擇的編碼正確,則在字符串中包含'\\xf2''ò'字符也將是正確的。 它仍然是一個字符。 'ò''\\xf2''\ò''\\U000000f2'只是在(unicode)字符串文字中表示相同單個字符的4種不同方式。 此外,len將為4,而不是5。

     print(ord(character_string[0])) # will be 242 print(hex(ord(character_string[0]))) # will be 0xf2 print(len(character_string)) # will be 4 

    如果您實際觀察到長度為5,則可能是在錯誤的位置觀察到的。 可能是在將字符串編碼為UTF-8或通過打印到UTF-8終端隱式編碼為UTF-8之后。

    請注意,更改默認I / O編碼時,輸出到外殼的字節數有所不同:

     PYTHONIOENCODING=UTF-8 python3 -c 'print(b"\\xf2a27".decode("latin1"), end="")' | wc -c # will output 5 PYTHONIOENCODING=latin1 python3 -c 'print(b"\\xf2a27".decode("latin1"), end="")' | wc -c # will output 4 

理想情況下,應該將原始字節轉換為它們代表的正確數據類型之后執行比較。 這使您的代碼更具可讀性,更易於維護。

根據一般經驗,應該始終在收到原始字節后將其轉換為實際的(抽象的)數據類型。 然后將其保留在該抽象數據類型中,以便進行盡可能長的處理。 如有必要,將其轉換回輸出的一些原始數據。

暫無
暫無

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

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