今天在使用python处理字符串时出现了一个如下错误
<code>unicodedecodeerror ascii codec can’t decode byte 0xd7 in position 4 ordinal not in range(128) </code>
从字面意思来看很显然是字符编码问题,然后百度了好多解决方案,根本不靠谱,最终折腾了半天还是解决了,记录一下
还是按照国际惯例,先描述一下应用场景:在对Apk的so加密保护中,有这么一个过程,将dex通过baksmali.jar反编译后得到的smali文件中,判断用户输入的待保护的so列表soList中
的so是否被调用,我们知道用户输入的so一般形如libxxx.so的格式,而java调用语句则是System.loadLibrary(“xxx”);的形式,即去除了前面的lib和.so后缀。反映到smali代码中就是如下的形式:
<code>const-string v0, "xxx"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
</code>
其中的xxx就是so列表中去除了前面的lib和.so后缀的so名称。那么这里就存在一个场景就是遍历修正用户输入后的so列表,然后在smali文件中判断是否存在调用该so的代码,即是否存在形如上述两条语句的代码,那么我们需要做的某一步就是构造出上述两个语句来,即讲so列表中的so与字符串const-string v0,相连接,刚开始以为很简单,不就是如下代码就可以吗?
<code>soCode = 'const-string v0, '+'"'+loadSo+'"' </code>
但是运行时出现开头提到的错误,很显然错误说的是编码问题,然后百度了一下,都说要在python文件开头加上utf-8注释之类的语句,或者说是使用如下语句:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
事实上没任何作用,仍然报开头提到的错误。那么我们仔细思考下为何会报那个错误,难道不应该是字符串的连接那么简单吗?事实证明不是那么简单,因为python中的list列表中存储的虽然是字符串,但是在python内部是使用unicode表示的,因此不能直接将一个list列表中的字符串与''的字符串相连接,因为这两种字符串可能属于不同的编码格式,是不能够直接相连接的,str与unicode之间的关系如下所示:
<code>str -> decode('the_coding_of_str') -> unicode
unicode -> encode('the_coding_you_want') -> str
</code>
也就是说str是字节串,是unicode经过编码(encode)后的字节组成的,这两者之间通过 decode/encode相互转化,那么知道了具体原因自然就知道该如何解决了,代码如下
<code>soCode = 'const-string v0, '+'"'+loadSo.encode('utf-8')+'"'
</code>
将list列表中的unicode先encode为字符串,然后再与‘xxx’字符串相连接,所以以后大家遇到这个问题,就不要相信网上的谣言说在python文件开头加上utf-8的注释,一定要弄清楚处理的字符串是str类型还是unicode类型,判断方式是使用type
<code> s = '中文'
s = u'中文'.encode('utf-8')
>>> type('中文')
<type 'str'>
s = u'中文'
s = '中文'.decode('utf-8')
s = unicode('中文', 'utf-8')
> > > type(u'中文') <type 'unicode'>
</code>
看似都是字符串,一个是str类型一个是unicode类型,总之要搞明白要处理的是str还是unicode, 使用对的处理方法(str.decode/unicode.encode)
一个和本内容相关的传送门:python进阶编码处理小结
文章评论