苦于utf-16编码/解码

时间:2018-09-21 06:55:46

标签: python utf-16

我正在解析具有一些UTF-16编码字符串的文档。

我有一个包含以下内容的字节字符串:

my_var = b'\xc3\xbe\xc3\xbf\x004\x004\x000\x003\x006\x006\x000\x006\x00-\x001\x000\x000\x003\x008\x000\x006\x002\x002\x008\x005'

转换为utf-8时,我得到以下输出:

print(my_var.decode('utf-8'))
#> þÿ44036606-10038062285

前两个字符þÿ表示它是UTF-16BE as indicated on Wikipedia

的BOM

但是,我不了解的是,如果我尝试这样的UTF16 BOM:

if value.startswith(codecs.BOM_UTF16_BE)

这将返回false。实际上,打印codecs.BOM_UTF16_BE不会显示相同的结果:

print(codecs.BOM_UTF16_BE)
#> b'\xfe\xff'

为什么?我怀疑高端有一些相关问题,但不确定如何解决。

已经有一些提及如何在Stackoverflow上解码UTF-16的内容(如this one),并且都说了一件事:使用utf-16和Python进行解码将处理BOM。

...但这对我不起作用。

print(my_var.decode('utf-16')
#> 뻃뿃㐀㐀 ㌀㘀㘀 㘀ⴀ㄀  ㌀㠀 㘀㈀㈀㠀㔀

但是使用UTF-16BE:

print(my_var.decode('utf-16be')
#> 쎾쎿44036606-10038062285

(未删除物料清单)

并使用UTF-16LE:

print(my_var.decode('utf-16le')
#> 뻃뿃㐀㐀 ㌀㘀㘀 㘀ⴀ㄀  ㌀㠀 㘀㈀㈀㠀㔀

因此,由于我无法解释的原因,仅使用.decode('UTF-16')对我不起作用。为什么?

更新

原始的源字符串不是我提到的,而是这个:

source = '\376\377\0004\0004\0000\0003\0006\0006\0000\0006\000-\0001\0000\0000\0003\0008\0000\0006\0002\0002\0008\0005'

我使用以下方法进行了转换:

def decode_8bit(cls, match):
    value = match.group().replace(b'\\', b'')
    return chr(int(value, base=8)).encode('utf-8')

my_var = re.sub(b'\\\\[0-9]{1,3}', decode_8bit, source)

也许我在这里做错了什么?

2 个答案:

答案 0 :(得分:1)

如果您使用 CP1252 编码,那么þÿ表示UTF-16BE的BOM是正确的。

区别如下:

您的第一个字节为0x C3 ,二进制为11000011。

  • UTF-8

设置了前两位,表示您的UTF-8字符长2个字节。 第一个字符为 0xC3 0xBE ,对于UTF-8,为þ。

  • CP1252

CP1252始终为1个字节长,并且对于0xC3返回Ã

但是,如果您在链接的BOM表中查找0xC3,则不会找到任何匹配的编码。 看起来一开始没有BOM。

使用默认编码可能是可行的方式,对于Windows,这是UTF-16LE

添加原始来源后进行编辑

您对UTF-8进行编码会破坏BOM,因为它不是有效的UTF-8。尝试避免解码并传递字节列表。

OPs解决方案:

bytes(int(value, base=8))

答案 1 :(得分:0)

按照@Tomalak和@Hyarus的要求,这是我遇到问题的原因:

解码8位值时,我以UTF-8编码返回它们:

def decode_8bit(cls, match):
    value = match.group().replace(b'\\', b'')
    return chr(int(value, base=8)).encode('utf-8')

my_var = re.sub(b'\\\\[0-9]{1,3}', decode_8bit, source)

由于未使用UTF-8(duh)对其进行编码,因此这弄乱了返回的数据。因此正确的代码应该是:

def decode_8bit(cls, match):
    value = match.group().replace(b'\\', b'')
    return bytes(int(value, base=8))

my_var = re.sub(b'\\\\[0-9]{1,3}', decode_8bit, source)

希望对其他人有所帮助...祝编码愉快! :/