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

2018-03-20 12:35:57 +08:00
 Mavious
限: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 里运行后变成大乱码
湖州新城建

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

求怎么改才能让它输出中文?
3457 次点击
所在节点    Python
19 条回复
lhx2008
2018-03-20 12:40:04 +08:00
直接 decode 不行吗
jasonyang9
2018-03-20 12:42:41 +08:00
湖州新
woha
2018-03-20 12:42:50 +08:00
@lhx2008 应该可以的吧
lastpass
2018-03-20 12:43:58 +08:00
"湖州新�" ??直接转就好
Mavious
2018-03-20 12:45:49 +08:00
@lhx2008
不行,直接 decode 会报 AttributeError: 'str' object has no attribute 'decode'
因为 str 是不能解码的。这是 py3 的特性,py2 就没这个错了。(这就是我为此浪费了几个小时的弯路)
lhx2008
2018-03-20 12:46:26 +08:00
cmd 里面乱码的话,是什么环境?
signxer
2018-03-20 12:48:42 +08:00
str(b'\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0','utf-8'),三个组成一个汉字,所以你这只有 11 个少一个,我只取了 9 个
am241
2018-03-20 12:48:45 +08:00
b'\xe6\xb9\x96\xe5\xb7\x9e\xe6\x96\xb0\xe5\x9f'.decode('utf-8', errors='ignore')
Mavious
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
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
2018-03-20 13:53:14 +08:00
@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
2018-03-20 14:09:06 +08:00
想知道你爬下来是句字符串吗? 不一般都是 bytes 吗
Mavious
2018-03-20 14:23:52 +08:00
@SuT2i 是,因为 type()看过类型。告诉我是 str。而且后面涉及切割什么的,别的也不好使啊。

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

无论如何,十分感谢你的帮助!!!谢谢,谢谢!!
ArianX
2018-03-20 15:15:05 +08:00
bytes.fromhex(str).decode('utf-8', errors='ignore'),这样可以吧
ArianX
2018-03-20 15:16:49 +08:00
额,应该是这样,bytes.fromhex(str.replace('\x','')).decode('utf-8', errors='ignore')
conn4575
2018-03-20 15:21:56 +08:00
了解一下内置的 struct 库
ae86
2018-03-20 17:05:32 +08:00
ae86
2018-03-20 17:09:40 +08:00
>>> 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
2018-03-20 17:48:46 +08:00
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'))

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/439667

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX