V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Mavious
V2EX  ›  Python

十六进制编码 str 转汉字的方法?!

  •  
  •   Mavious · 2018-03-20 12:35:57 +08:00 · 3355 次点击
    这是一个创建于 2226 天前的主题,其中的信息可能已经有所发展或是发生改变。
    限:py3 环境( py2 和 3 对于编码的处理是不一样的,很多教程根本不告诉你应用于哪个版本,害得我走了几个小时弯路!)
    用 cmd 运行。
    -----------------------------------------

    爬虫爬到了一串\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f 数据,str 类型,这应该是 16 进制编码的汉字(嗯……应该是,我对编码一窍不通)
    现在我想把它转成中文,方便和别的参数拼接成一串完整 URL 让 requests 访问。

    在 B 乎找了个主意
    https://www.zhihu.com/question/26921730

    于是我把代码改成这样
    data = ('\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f').encode('UTF-8').decode('unicode_escape')
    print (data)

    cmd 里运行后变成大乱码
    湖州新城建

    我怀疑是编码不对,然而我对编码一窍不通,于是卡住了。

    求怎么改才能让它输出中文?
    第 1 条附言  ·  2018-03-20 14:26:02 +08:00
    字符串.replace('\\x','%')
    替换了,让浏览器给我解码去了,勉强曲线救国。了结。

    ----------------------

    真的很讨厌编码!!讨厌讨厌!!这么个事儿我从昨天下午研究到第二天中午。
    19 条回复    2018-03-20 17:48:46 +08:00
    lhx2008
        1
    lhx2008  
       2018-03-20 12:40:04 +08:00 via Android
    直接 decode 不行吗
    jasonyang9
        2
    jasonyang9  
       2018-03-20 12:42:41 +08:00
    湖州新
    woha
        3
    woha  
       2018-03-20 12:42:50 +08:00 via Android
    @lhx2008 应该可以的吧
    lastpass
        4
    lastpass  
       2018-03-20 12:43:58 +08:00 via Android
    "湖州新�" ??直接转就好
    Mavious
        5
    Mavious  
    OP
       2018-03-20 12:45:49 +08:00
    @lhx2008
    不行,直接 decode 会报 AttributeError: 'str' object has no attribute 'decode'
    因为 str 是不能解码的。这是 py3 的特性,py2 就没这个错了。(这就是我为此浪费了几个小时的弯路)
    lhx2008
        6
    lhx2008  
       2018-03-20 12:46:26 +08:00 via Android
    cmd 里面乱码的话,是什么环境?
    signxer
        7
    signxer  
       2018-03-20 12:48:42 +08:00   ❤️ 1
    str(b'\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0','utf-8'),三个组成一个汉字,所以你这只有 11 个少一个,我只取了 9 个
    am241
        8
    am241  
       2018-03-20 12:48:45 +08:00   ❤️ 1
    b'\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f'.decode('utf-8', errors='ignore')
    Mavious
        9
    Mavious  
    OP
       2018-03-20 13:37:48 +08:00
    @am241 @signxer

    你好,方法很暴力很有效。

    但是我看到文档里提到,b 后面必须跟随单双引号

    “ Python 对 bytes 类型的数据用带 b 前缀的单引号或双引号表示”
    https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431664106267f12e9bef7ee14cf6a8776a479bdec9b9000


    实际上,\xe6\xb9\x96\xe5\xb7 ……是一串可变数据,我给它命名为 productName 方便引用。但是 b 后面一跟随变量就报错。

    print (b(productName).decode('utf-8', errors='ignore'))

    NameError: name 'b' is not defined

    如文档所说,单双引号里面必须存放写死的了数据,不能写变量。
    如果 b 前缀只认可单双引号的话,变量这种东西该如何解呢?

    谢谢。我是萌新,不好意思。
    binux
        10
    binux  
       2018-03-20 13:52:06 +08:00
    '\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f'.encode('latin_1').decode('utf8', 'ignore')
    am241
        11
    am241  
       2018-03-20 13:53:14 +08:00   ❤️ 2
    @Mavious b'...'表示后面是 bytes 类型的数据,b'\x00'和 bytes([0])等价

    b(productName) 函数调用或者创建实例

    可以这样:
    # st = r'\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f'
    bytes([int(i, 16) if i else None for i in st.split(r'\x')][1:]).decode('utf-8', errors='ignore')
    或者:
    # st = r'\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f'
    eval("b'"+(st)+"'").decode('utf-8', errors='ignore')
    SuT2i
        12
    SuT2i  
       2018-03-20 14:09:06 +08:00
    想知道你爬下来是句字符串吗? 不一般都是 bytes 吗
    Mavious
        13
    Mavious  
    OP
       2018-03-20 14:23:52 +08:00
    @SuT2i 是,因为 type()看过类型。告诉我是 str。而且后面涉及切割什么的,别的也不好使啊。

    @am241 十分感谢。不过我太菜了,看了半个小时不是很懂。
    在看懂的过程中,突然想了个方法:把\x 替换成%,传递给浏览器地址栏
    productName.replace('\\x','%')
    让浏览器给我解码去了。然后就算勉强曲线救国了。

    无论如何,十分感谢你的帮助!!!谢谢,谢谢!!
    ArianX
        14
    ArianX  
       2018-03-20 15:15:05 +08:00 via Android
    bytes.fromhex(str).decode('utf-8', errors='ignore'),这样可以吧
    ArianX
        15
    ArianX  
       2018-03-20 15:16:49 +08:00 via Android   ❤️ 1
    额,应该是这样,bytes.fromhex(str.replace('\x','')).decode('utf-8', errors='ignore')
    conn4575
        16
    conn4575  
       2018-03-20 15:21:56 +08:00 via Android   ❤️ 1
    了解一下内置的 struct 库
    ae86
        17
    ae86  
       2018-03-20 17:05:32 +08:00   ❤️ 1
    ae86
        18
    ae86  
       2018-03-20 17:09:40 +08:00   ❤️ 1
    >>> s=r'\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f\x8e\xe5\xbb\xba'
    >>> eval('b"'+s+'"').decode('utf-8')
    '湖州新城建'
    狐吧吧友雷吼啊,网上找的方法,我也不太会 py,不知道这样行不行。
    chenstack
        19
    chenstack  
       2018-03-20 17:48:46 +08:00   ❤️ 1
    python3 的 str 类型内部存的是 unicode, str.encode 默认编码是 utf-8,'\xe6\xb9\x96'.encode()结果并不是 b'\xe6\xb9\x96'

    说一下结论,个人认为比较好的方式,使用 latin-1 或 charmap 编码器编码到相同字节的 bytes:
    text = '\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f\x8e\xe5\xbb\xba'
    print(text.encode('latin-1').decode('utf-8'))

    或者手动映射:
    print(bytes(map(ord, text)).decode('utf-8'))
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3804 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 10:34 · PVG 18:34 · LAX 03:34 · JFK 06:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.