我正在解析具有一些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)
也许我在这里做错了什么?
答案 0 :(得分:1)
如果您使用 CP1252 编码,那么þÿ表示UTF-16BE的BOM是正确的。
区别如下:
您的第一个字节为0x C3 ,二进制为11000011。
设置了前两位,表示您的UTF-8字符长2个字节。 第一个字符为 0xC3 0xBE ,对于UTF-8,为þ。
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)
希望对其他人有所帮助...祝编码愉快! :/