【问题标题】:String to Bytes Python without change in encoding字符串到字节 Python,无需更改编码
【发布时间】:2018-06-30 05:32:41
【问题描述】:

我有这个问题,我不知道如何解决它。我有这个字符串:

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。

【问题讨论】:

  • 请注意,“不改变编码” 是一种误导性要求。将字符串转换为字节或反之亦然时,您必须考虑编码以便执行转换。

标签: python string python-3.x byte


【解决方案1】:

如果不考虑编码,您无法将字符串转换为字节或字节转换为字符串。关于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,这就解释了为什么将其编码为字节时会出现这种情况。但它也有 0x00C4 的编码,例如 UTF-16。


至于如何正确地解决这个问题,让你得到想要的输出,目前还没有明确的正确答案。 Kasramvd 提到的解决方案也有些不完善。如果您了解raw_unicode_escape 编解码器in the documentation

raw_unicode_escape

其他代码点使用 \uXXXX\UXXXXXXXX 的拉丁语 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 字符,那么您很可能一开始就不需要使用字符串。由于您实际上正在处理某种字节,因此您应该首先查看是否不能简单地将这些值作为字节检索。这样一来,您就不会在那里引入 两个 级别的编码,您可能会通过误解输入来破坏数据。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • @Jean-FrançoisFabre 在这种情况下更好!
    • @avan989 不要“谢谢”​​。接受答案。
    • 那些字符串 字节转换真的很糟糕 :) 你能解释一下为什么执行默认编码会添加这个垃圾吗? (诚​​实的问题,我不知道答案)。如果你不能,好吧,没关系。
    • @Jean-FrançoisFabre 您所说的 helltrash 究竟是什么意思,因为这种转换存在很多问题,具体取决于具体情况! ;))
    • @Jean-FrançoisFabre 恕我直言,主要问题是字节是不可变的整数序列,正如文档中所述,字节文字中只允许使用 ASCII 字符(无论声明的源代码编码如何)。任何超过 127 的二进制值都必须使用适当的转义序列输入字节文字。现在,特别是在 python-3.X 中,您需要在所有这些转义文字和所有可能的 unicode 之间进行转换,还要在字符串和整数之间转换类型等。所有这些过程都需要大量的检查和时间。跨度>
    猜你喜欢
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多