Jython初始化乱码问题

实际上默认情况下启动Jython是不会出现UnicodeDecodeError异常的,但是有个同事的电脑上的用户名是中文的,你懂的。然后就一直启动不了,急死人了。
默认情况下,Python启动的时候会加载site模块,在其main函数中会进行如下的操作:

del sys.setdefaultencoding

把对应的设置默认编码的函数删除。
因此,我们有:

>>> import sys  
>>> sys.getdefaultencoding()  
'ascii'

而在其execsitecustomize函数中会导入1个sitecustomize的模块,我们可以在这里进行操作。
我们编写1个该脚本,其内容为:

#coding:utf-8  
import sys  
reload(sys)  
sys.setdefaultencoding("gbk")

然后进行编译:

  
λ java -jar jython-standalone-2.7.0.jar -m compileall sitecustomize.py  

编译完成后将其class文件丢在jython的lib目录下即可,此时有:

λ java -jar jython-standalone-2.7.0.jar  
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)  
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_181  
Type "help", "copyright", "credits" or "license" for more information.  
>>> import sys  
>>> sys.getdefaultencoding()  
'GBK'

然而上述方法无法解决用户目录为中文的问题。因此有:

λ java -jar jython-standalone-2.7.0.jar  
Exception in thread "main" Traceback (most recent call last):  
  File "E:\jython-standalone-2.7.0.jar\Lib\site.py", line 585, in <module>  
  File "E:\jython-standalone-2.7.0.jar\Lib\site.py", line 567, in main  
  File "E:\jython-standalone-2.7.0.jar\Lib\site.py", line 300, in addusersitepackages  
  File "E:\jython-standalone-2.7.0.jar\Lib\site.py", line 289, in getusersitepackages  
  File "E:\jython-standalone-2.7.0.jar\Lib\sysconfig.py", line 416, in get_path  
  File "E:\jython-standalone-2.7.0.jar\Lib\sysconfig.py", line 407, in get_paths  
  File "E:\jython-standalone-2.7.0.jar\Lib\sysconfig.py", line 180, in _expand_vars  
  File "E:\jython-standalone-2.7.0.jar\Lib\sysconfig.py", line 154, in _subst_vars  
  File "E:\jython-standalone-2.7.0.jar\Lib\sysconfig.py", line 154, in _subst_vars  
UnicodeEncodeError: 'ascii' codec can't encode characters in position 9-10: ordinal not in range(128)

我们使用-S选项屏蔽加载site模块,然后查看其用户名称:

>>> import getpass  
>>> getpass.getuser()  
u'\u6e17\u900f'

实际上问题在于sysconfig模块中有:

def _subst_vars(s, local_vars):  
    try:  
        return s.format(**local_vars)

它会调用site模块下的getuserbase函数:

def getuserbase():  
    global USER_BASE  
    if USER_BASE is not None:  
        return USER_BASE  
    from sysconfig import get_config_var  
    USER_BASE = get_config_var('userbase')  
    return USER_BASE

因此我们需要在其返回之前对指定的字符串进行编码为cp936,然后再打包为jar,于是有:

λ java -jar jython-fix-2.7.0.jar  
>>> import sys  
>>> sys.getdefaultencoding()  
'GBK'

此时直接就是GBK编码了。
另外需要注意的是,在Jython中默认的平台信息会丢失:

>>> import platform  
>>> platform.system()  
'Java'

可以看到此时就是1个Java的系统,为此我们需要调用Java来获取其详细信息:

>>> from java.lang import System  
>>> System.getProperty("os.name")  
u'Windows 10'

这样我们就得到了当前系统为Windows。

若文章对您有帮助,请打赏1块钱。您的支持,可以让我分享更多精彩的文章。转载请注明来源


知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。