Python3:读取utf8编码的字节串

时间:2017-12-12 22:56:50

标签: python python-3.x encoding utf-8

我的程序使用“iwlist scan”的输出生成报告。 除非网络名称(ESSID)包含非Ascii字符,否则它可以正常工作 IEEE802.11声明ESSID可能包含UTF8字符。但是,这些essid被iwlist报告为编码的字节串。例如:
      ESSID: “F \ XC3 \ xAAte”
\ xC3 \ xAA实际上是“ê”的UTF-8编码 我找不到指定“打开”这些字节串应自动转换为UTF-8字符的方法 问题:解决我问题的最灵活方法是什么?

PS:作为测试案例,我将以下行放在一个文件中(比如xx):
ESSID: “F \ XC3 \ xAAte”
我执行:
open('xx','rb')。read()。decode('UTF-8')
我的结果是:
'ESSID:“f \ xC3 \ xAAte”\ n'

3 个答案:

答案 0 :(得分:1)

这实际上是一个两步过程:将\xNN代码转换为等效字节值,然后将这些字节从UTF-8转换为Unicode字符。 Python提供了unicode_escape编解码器,使流程更简单。不幸的是,您需要一个额外的步骤 - 它不会将\xNN转换为字节,它会将它们转换为字符,您需要将那些转换回等效字节。

所以你最终得到了3步转化。编码到latin1是将字符转换为字节的黑客攻击。它的工作原理是因为Unicode使用Latin-1编码作为其前256个代码点,为您提供1:1映射。

with open(filename, 'rb') as f:
    essid_raw = f.read()
    essid = essid_raw.decode('unicode_escape').encode('latin1').decode('utf-8')


>>> essid_raw = b'ESSID:"f\xC3\xAAte"'
>>> essid = essid_raw.decode('unicode_escape').encode('latin1').decode('utf-8')
>>> print(essid)
ESSID:"fête"

答案 1 :(得分:0)

据我了解你的问题:

您的文件看起来根本没有Unicode字符,但它有一个转义字符串。因此,实际上有8个字符ê,而不是一个\xC3\xAA符号。因此,不应使用.decode("utf-8")从Unicode解码,而应使用unicode转义字符(.decode('unicode_escape')进行解码。

为了尝试这个,我用一个字符串创建了一个文件:

ESSID:"f\xC3\xAAte"

然后此脚本打印以下内容:

>>> open( 'file','rb').read().decode('UTF-8')
ESSID:"f\xC3\xAAte"

如果您使用unicode_escape,您将获得

>>> open( 'file','rb').read().decode('unicode_escape')
ESSID:"fête"

答案 2 :(得分:0)

我正在回答自己 找不到python解决方案所以我开发了我的 方法是删除'\ x'并将2个十六进制字符转换为一个字节。重复每个\ x。

def adapt( tb):
  # this function converts the weird UTF8 escaping used by 'iwlist scan'
  # iwlist outputs "f\xC3\xAAte" instead of "fête"
  # caution : input is not sanitized 
  i = 0
  while True:
    # suppress \x and replace the following 2 characters by their hex value 
    i = tb.find( b'\\\x', i)
    if i < 0: break
    tb = tb[:i] + bytes( [int( tb[ i+2:i+4], 16)]) + tb[i+4:]
    i += 1     # skip the preceding sequence
  return tb

用法:

txt = adapt( open( 'xx','rb').read()).decode()
print( txt)
ESSID:"fête"  

这是一个丑陋的黑客,但它工作正常。我很乐意更喜欢更好的解决方案 谢谢你的回答。