字符串到字节Python而不改变编码

时间:2018-01-21 13:11:32

标签: python string python-3.x byte

我有这个问题,我无法弄清楚如何解决它。我有这个字符串:

data = '\xc4\xb7\x86\x17\xcd'

当我尝试编码时:

data.encode()

我得到了这个结果:

b'\xc3\x84\xc2\xb7\xc2\x86\x17\xc3\x8d'

我只想要:

b'\xc4\xb7\x86\x17\xcd'

任何人都知道原因以及如何解决这个问题。该字符串已存储在变量中,因此我无法在其前面添加文字b。

2 个答案:

答案 0 :(得分:8)

如果没有考虑编码,则无法将字符串转换为字节或字节为字符串。关于bytes类型的整点是与编码无关的字节序列,而strUnicode code points的序列,其中按设计没有唯一的字节表示

因此,当您想要将一个转换为另一个时,必须明确 要使用哪种编码来执行此转换。转换为字节时,您必须说明如何将每个字符表示为字节序列;当你从字节转换时,你必须说出用什么方法将这些字节映射成字符。

如果你没有指定编码,那么UTF-8是默认值,这是一个理智的默认值,因为UTF-8无处不在,但它也只是一个许多有效的编码。

如果您使用原始字符串'\xc4\xb7\x86\x17\xcd',请查看这些字符代表的Unicode代码点。 \xc4例如LATIN CAPITAL LETTER A WITH DIAERESIS,即Ä。该字符碰巧以UTF-8编码为0xC3 0x84,这解释了为什么这是你将其编码为字节时得到的。但它的UTF-16编码也为0x00C4

至于如何正确解决 以便获得所需的输出,没有明确的正确答案。 Kasramvd提到的解决方案也有些不完美。如果您阅读了raw_unicode_escape编解码器in the documentation

  

raw_unicode_escape

     

其他代码点使用\uXXXX\UXXXXXXXX进行Latin-1编码。现有的反斜杠不会以任何方式转义。它用于Python pickle协议。

所以这只是一个Latin-1 encoding,它有一个内置的回退字符。我认为这种后备对你的目的有些害。对于无法表示为\xXX序列的Unicode字符,这可能会有问题:

>>> chr(256).encode('raw_unicode_escape')
b'\\u0100'

因此,代码点256 显式位于Latin-1的之外,导致raw_unicode_escape编码返回字符串'\\u0100'的编码字节,从而转换为一个字符到6个字节,与原始字符几乎没有关系(因为它是一个转义序列)。

所以如果你想在这里使用Latin-1,我建议你明确地使用它,而不要让raw_unicode_escape的转义序列回退。当尝试将代码点转换为Latin-1区域之外时,这只会导致异常:

>>> '\xc4\xb7\x86\x17\xcd'.encode('latin1')
b'\xc4\xb7\x86\x17\xcd'
>>> chr(256).encode('latin1')
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    chr(256).encode('latin1')
UnicodeEncodeError: 'latin-1' codec can't encode character '\u0100' in position 0: ordinal not in range(256)

当然,Latin-1区域之外的代码点是否会导致问题取决于该字符串的实际来源。但是如果你能保证输入只包含有效的Latin-1字符,那么你很可能不需要首先使用字符串。由于您实际上正在处理某种字节,因此您应该首先查看是否不能简单地将这些值作为字节检索。这样你就不会引入两个级别的编码,你可以通过误解输入来破坏数据。

答案 1 :(得分:2)

您可以使用'raw_unicode_escape'作为编码:

In [14]: bytes(data, 'raw_unicode_escape')
Out[14]: b'\xc4\xb7\x86\x17\xcd'

如评论中所述,您还可以将编码直接传递给字符串的encode方法。

In [15]: data.encode("raw_unicode_escape")
Out[15]: b'\xc4\xb7\x86\x17\xcd'