Python 和 Linux locale 学习笔记
2016-08-21 13:03
519 查看
遇到一个问题
python 中定义了unicode字符串。server A
unicode_string=u"hello \u2026" print unicode_string
server A output
hello …
server B
unicode_string=u"hello \u2026" print unicode_string
server B output
Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 6: ordinal not in range(128)
这个问题让我对Linux encode和Python encode又个初步调查。
linux encode
1. 首先什么是 unicode 和 utf-8
首先电脑存放的都是byte,ascii code 将符号,字符以一个byte来表示。8个‘0‘,‘1‘ 不同顺序排列出不同的字符和符号。但是,一个byte并不能将世界上不同国家的文字和符都囊括在内。这时就出现了各种个样的编码标准。
最为普遍的编码标准是unicode, unicode 简单的来说是一种编码标准。它把一个文字,符号按照最多4个byte来编码。
但是编码后的字符或者符号电脑怎么认识呢(电脑只认识byte)?所以人们又发明了utf-8这种编码格式。unicode以一个统一的编码规范编程多个不同数量的byte,同时电脑以这个统一的规范读取和打印。
有篇简单易懂的好文大家看看:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
2. Linux 上的编码
Linux 上有个查看本地话的工具:localelocale 命令 可以查看所有本地化设置, 这里我分别在serverA和serverB上执行了locale。
发现serverA和serverB配置如下。
server A locale
VirtualBox:~$ locale LANG=en_US.UTF-8 LANGUAGE= LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL=en_US.UTF-8 VirtualBox:~$ locale charmap UTF-8
server B locale
VirtualBox:~$ locale LANG= LANGUAGE= LC_CTYPE="C" LC_NUMERIC="C" LC_TIME="C" LC_COLLATE="C" LC_MONETARY="C" LC_MESSAGES="C" LC_PAPER="C" LC_NAME="C" LC_ADDRESS="C" LC_TELEPHONE="C" LC_MEASUREMENT="C" LC_IDENTIFICATION="C" LC_ALL=C VirtualBox:~$ locale charmap ANSI_X3.4-1968
这里解释下这里的部分关键参数:
LANG="en_US.UTF-8" # 它的值用于指定下面环境变量没有设置的所有变量值。如果指定了上面任何一个变量的值,则会废除对应的LANG值的缺省设置。 LC_CTYPE="zh_CN.UTF-8" # 用于字符分类和字符串处理,控制所有字符的处理方式,包括字符编码,字符是单字节还是多字节,如何打印等。 LC_NUMERIC="en_US.UTF-8" # 指定使用某区域的非货币的数字格式 LC_TIME="en_US.UTF-8" # 指定使用某区域的日期和时间格式 LC_COLLATE="en_US.UTF-8" # 指定使用某区域的排序规则 LC_MONETARY="en_US.UTF-8" # 指定使用某区域的货币格式 LC_MESSAGES="en_US.UTF-8" # 用于控制程序输出时所使用的语言,主要是提示信息,错误信息,状态信息, 标题,标签, 按钮和菜单等。 LC_PAPER="en_US.UTF-8" # 指定使用某区域的纸张大小 LC_NAME="en_US.UTF-8" # 指定使用某区域的姓名书写方式 LC_ADDRESS="en_US.UTF-8" # 指定使用某区域的地址格式和位置信息 LC_TELEPHONE="en_US.UTF-8" # 指定使用某区域的电话号码格式 LC_MEASUREMENT="en_US.UTF-8" # 指定使用某区域的度量衡规则 LC_IDENTIFICATION="en_US.UTF-8" # 对 locale 自身信息的概述 LC_ALL= # 它不是环境变量, b47e 只是一个宏,可使用setlocale设置所有的LC_*环境变量。这个变量设置之后,可以废除LC_*和LANG的设置值,使得这些变量的设置值与LC_ALL的值一致。
当一个程序找环境变量值时,按照下面优先级
[1] LANGUAGE [2] LC_ALL [3] LC_xxx [4] LANG
这里有个charmap,charmap这个文件定义了Locale中所有字符与内码的对应关系。通常是保存在系统的/usr/share/i18n/charmaps目录下(定义该Locale所支持的字符集中的每个字符)。比如说 2026是unicode省略号的意思如果charmap指定的对应关系中包涵2026和内码的对应关系则2026可以被解析。如果不包含则解析不了(UTF-8 中包涵,而ANSI_X3.4-1968中不包含并不能对unicdoe解码)。
所以上面两个服务器不同的结果很容易看出是为什么。此时看以用
python -c “import sys; print sys.stdout.encoding” 查看charmp的值。因为ANSI_X3.4-1968不能对nuicode 编码解码导致。相应的值打印不出来。
1.这里大家可以显示地设置Python的编码PYTHONIOENCODING。
在 ViM 中运行 :!python -c “import sys; print(sys.stdout.encoding)” 时,输出可能是
ANSI_X3.4-1968 (即使你设置了正确的Locale) . 把 PYTHONIOENCODING 变量设置成 utf-8
可以规避这个问题.
2.大家可以在程序中显示的加上encode(‘utf-8’)
unicode_string=u"hello \u2026".encode('utf-8')
3.大家可以设置locale
LC_ALL=en_US.utf8 export LC_ALL
这里有些参考性的资料大家可以看下
https://wiki.archlinux.org/index.php/Locale_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
https://www.ibm.com/developerworks/cn/linux/l-cn-linuxglb/
https://www.ibm.com/developerworks/cn/linux/i18n/unicode/linuni/
http://www.programgo.com/article/41343600592/
https://linux.cn/lfs/LFS-BOOK-7.7-systemd/chapter07/locale.html
Python 上的编码
这里有个问题值得注意Python报的错误和ANSI_X3.4-1968 一点关系也没有。而是一个’ascii’问题。这里就涉及到了Python的编码。
import sys import locale #当unicode字符做连接时,python会隐性的做encode, #大概是Python 发现程序中有文字要和unicode做连接,而且也没有指定是unicode。python会尝试用getdefaultencoding进行编码后,在做处理。 #这里的encode的编码格式是有下面参数决定的。 sys.getdefaultencoding() #eg 这里会给hello编码,编码格式由sys.getdefaultencoding()这个值决定。 u"\u2026" + "hello" #if sys.getdefaultencoding() is ascii, this cause error #这里‘中文‘不能用ascii编码,会报错。要指明中文是unicode才行 print "中文"+u"\u2026" Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec cant decode byte 0xe4 in position 0: ordinal not in range(128) #指明中文是unicode,python知道‘中文‘不适ascii码,是unicode。所以不会再用默认格式编码。 a=u"中文"+u"\u2026" print a 中文… #this matter what is print out #same with 'print(sys.stdout.encoding)' #To control stdin.encoding and stdout.encoding you want to set PYTHONIOENCODING # 这里的到系统locale的值,这里的值和charmap一样, # 决定了你的"输出"和"输入"(both)。 lcoale.getpreferredencoding() # eg print u"\u2026"
我遇到的情况中,错误首先是被Python,捕捉到了,而且跑出了异常。
unicode_string=u"hello \u2026" print unicode_string
Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 6: ordinal not in range(128)
这里指明了时unicode,但是打印出来报ascii错。这种状况和做链接时相似。原因可能是系统使用locale.getpreferredencoding() 或者(sys.stdout.encoding)设置的是ANSI_X3.4-1968 编码方式,这个编码方式并不能编码unicode。
这里报错的‘ascii‘并不是setdefaultencoding中的ascii
Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print u"hello \u2026"
Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 6: ordinal not in range(128)
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> print u"hello \u2026"
Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 6: ordinal not in range(128)
>>> sys.setdefaultencoding('utf-8')
>>> print u"hello \u2026"
Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u2026' in position 6: ordinal not in range(128)
>>> sys.getdefaultencoding()
'utf-8'
那这个ascii是哪的呢?我暂时也不知道。求大神告知。
参考资料
python -c “import locale; print locale.getdefaultlocale()”
http://nedbatchelder.com/text/unipain.html
https://docs.python.org/2/howto/unicode.html
相关文章推荐
- linux下python学习笔记(十四)之备份实例2
- linux下python学习笔记(六)
- 一些关于Python的基础知识 - 千月的python linux 系统管理指南学习笔记(3)
- Python 创建、读取和写入文件以及yield关键字- 千月的python linux 系统管理指南学习笔记(14)
- IPython下目录的操作-魔力函数(cd pwd bookmark dhist )- 千月的python linux 系统管理指南学习笔记(7)
- linux下python学习笔记(十二)数据结构2
- python3.5学习笔记:linux6.4 安装python3 pip setuptools
- Python中使用函数 - 千月的python linux 系统管理指南学习笔记(4)
- python3.5学习笔记:linux6.4 安装python3 pip setuptools
- Python下字符串的创建和转义字符的使用 - 千月的python linux 系统管理指南学习笔记(10)
- linux下python学习笔记(十三)之备份实例1
- linux 学习笔记 (3) —— 使用python
- python 学习笔记 8 -- Python下调用Linux的Shell命令
- IPython(jupyter)简单介绍和基本交互操作 - 千月的python linux 系统管理指南学习笔记(5)
- linux+python+djiango+mysql编译安装学习笔记
- linux下python学习笔记(十六)
- python学习笔记-(1)linux下的helloworld
- 【python学习笔记】实现linux终端下的getch()函数
- IPython下字符串的简单处理 - 千月的python linux 系统管理指南学习笔记(8)
- IPython下执行shell命令-魔力函数(alias store rehash)- 千月的python linux 系统管理指南学习笔记(6)