Skip to content

Latest commit

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

#Python, UTF-8, and Chinese characters.

######Python的UTF-8编码问题比较让人抓狂, 我之前抓狂过很多次之后决定写一个wiki, ######主要是为了解决我们在Python编码过程中遇到的UTF-8中文乱码问题. ######PS1: 本WIKI不会对UTF-8具体的细节进行过多的说明, 主要是提供各种不同的情况情况该如何解决提供一些方法. ######PS2: 图省事的话直接看第3, 4点以及conclusion即可:)

1. 文件编码

  • 文件的编码方式是什么?ASCII(default)还是其他的?在vim下可以用:set fileencoding查看. 或者使用iconv: iconv -f utf8 filename 如果输出正常, 无错误, 无乱码, 那么该文件也应该是正确地以UTF-8的编码方式保存的. 如果打算使用utf编码,可以使用:set fileencoding=utf8进行指定,vim会负责完成转换工作.

  • 关于 [PEP-0263] 1建议是在文件的头两行显示指定文件编码,方式有如下几种:

    • # coding=<encoding name>
    • # -*- coding: <encoding name> -*-
    • # vim: set fileencoding=<encoding name> :
    • 第2种比较少见,第1种比较漂亮,第0种是我使用的:)
  • 文件编码的作用

    • 让阅读代码的人直到该文件的编码方式
    • 如果文件中有--显式--的需要特别编码处理的字符(如中文)时,通过指定文件的编码能够让editor知道如何处理,储存.
    • 显式具体指的是:
      • a = "我是中文"
      • a = u"我是中文"
  • Example:

File: 1-pyutf8.py#!/usr/bin/env python# encoding=utf-8 importosimportsysa="我是中文"b=u"我也是中文"os.write(sys.stdin.fileno(), a)
os.write(sys.stdin.fileno(), b)
printaprintb
  • 若缺少了了# encoding=utf-8 则文件在 执行时会出错: SyntaxError: Non-ASCII character '\xe6' in file 1-pyutf8.py on line 5, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

  • 此时是Python解析器报的错误,而出错的原因正是Python解析器没有找到合适的编码方法去解析代码. 注意: 此时,编码文件已经是正确地已UTF-8格式储存的, 只是Python不知道.所以需要显示地进行指定.

  • 另外,关于使用print/os.write, print会根据终端的环境进行一些编码换转, 或许会"欺骗"我们, os.write的结果则是比较准确, 真实的.

  • trick: 我们可以将字符串放如一个集合类型中,比如list. 然后再使用print打印该list, 这样可以得到真实的数据类型.

>>>a="中文">>>b=u"中文">>>c=u"sunus">>>printa, b, c中文中文sunus>>>print [a, b, c]
['\xe4\xb8\xad\xe6\x96\x87', u'\u4e2d\u6587', u'sunus']
  • 第二个print的结果可以知道, a为str, b, c均为unicode. 而第一个print则不会显示这些信息.

  • 在确定文件编码之后没问题之后,继续分析别的错误.

2. unicode , str and UTF-8

  • python2x里, 对于字符串有两个不同的类进行表示,分别是 unicodestr, 对应的Constructor分别是unicode(), str(), 而且, 他们都是由同一个基类 basestring 派生出来的. 顺便说一下,检验一个对象的正确方法是 isinstance(value, basestring)

  • unicode是为了处理多字节字符(如中文)而设计的, 对于ASCII字符来说, 他们没什么区别而且能够兼容, 但是, 当有出现中文时, 问题就出来了.

  • UTF-8是一个具体的unicode编码方式的实现.

  • 我们将 str 作为 可读 的字符串, unicode作为python内部对字符串的一种 抽象 实现并选择正确的储存方法, print var, 'xx', "xxx" 则都是str(没有打头的u)

3. encode and decode

  • encode: 是将unicode转换成str编码, 并且encoding参数为具体的实现, 如UTF-8

  • decode: 是将str转换成unicode编码, 并且encoding参数为具体的实现, 如UTF-8

  • 使用建议:

    • 对于unicode 尽量只让unicode对象存在于内存中, 打印输出, 网络传输, 写入文件, 之前 应该将其转换为 str, 而且, 含有非ASCII码字符的unicode字符串, 是 写不进文件 的.

    • 以str字符串形似, 或者通过外部手段(iconv, vim set fileencoding, etc)等方式形成的文件, 本身就能够 无障碍 地被读取.

    • unicode字符串, 只作为"中间态"使用.如

      a=u'OnlyIn内存'#if you want to see what's in a#use:ae=a.encode('utf8')
      #do whatever you want with a, net transporat or write to file.
    • 无encoding参数的encode, decode方法所使用的默认encoding为系统环境获取, 不建议使用.

4. Examples:

File: encode_or_decode_write.py#!/usr/bin/env python# encoding=utf-8importsysimportosimporttracebacksstr1="Most Normal String\n"sstr2="我是str string\n"ustr1=u"unicode string WITHOUT Chinese\n"ustr2=u"我是unicode string\n"deftest(new_file_name, method, *args):
try:
withopen(new_file_name, 'w') asf:
forsinargs:
so=ss=getattr(s, method)('utf-8')
f.write(s)
print'write', so, [so], method, 'succeed!'print'%s to %s'% (str(so.__class__), str(so.__class__))
except:
traceback.print_exc()
defmain():
ifsys.argv[1] =='encode':
test('str', 'encode', sstr1, sstr2)
test('uni', 'encode', ustr1, ustr2)
elifsys.argv[1] =='decode':
test('str', 'decode', sstr1, sstr2)
test('uni', 'decode', ustr1, ustr2)
else:
print'arg can only be decode or encode'main()
  • 执行 python encode_or_decode_write.py encode , sstr1, ustr1, ustr2 能够成功写入文件, sstr2 失败.

    • 对unicode使用encode使之变成可读, 可写, 可传输的str. 所以 ustr1, ustr2 均成功.
    • sstr1因为没有包含非ASCII字符, 所以也成功了. 而sstr1包含有中文, 失败. 一定不要使用unicode进行读写, 传输 等操作
  • 执行 python encode_or_decode_write.py decode , 只有sstr1, ustr1 能够成功写入, 因为他们没有非ASCII字符.

    • sstr2, decode之后变为unicode 该过程成功,失败是因为将unicode 写入文件
    • ustr2, decode则直接失败了, 对unicode进行decode操作, 本身就是有问题的嘛!

5. Conclusion:

  • 将unicode留在内存中
  • 读取, 写入文件, 网络传输使用str. 即 str_str = unicode_string.encode('utf8')

6. 有错误, 不清楚的地方欢迎请指出, 谢谢:)

About

how to play with python and UTF-8, especially with Chinese:)

Resources

Stars

11 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages