繁体   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