python_中文编码问题

https://www.cnblogs.com/yuguangchuan/p/4310952.html

什么是字符编码? 

      计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),如果要表示更大的整数,就必须用更多的字节。比如两个字节可以表示的最大整数是65535,4个字节可以表示的最大整数是4294967295

ASCII编码:

  由于计算机是美国人发明的,因此,最早只有127个字母被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母 的编码是65,小写字母 的编码是122

  但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。

  全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。

Unicode编码:

  因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。

ASCII编码和Unicode编码的区别:

  1)ASCII编码是1个字节,而Unicode编码通常是2个字节,举例如下。

  字母 用ASCII编码是十进制的65,二进制的01000001

  字符 用ASCII编码是十进制的48,二进制的00110000,注意字符 '0' 和整数 是不同的;

  汉字 中 已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101

  如果把ASCII编码的 用Unicode编码,只需要在前面补0就可以,因此, 的Unicode编码是00000000 01000001

UTF-8编码:

  新问题的出现:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。

  因此,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:

字符 ASCII Unicode UTF-8
    A 01000001 00000000 01000001 01000001
    中         - 01001110 00101101

11100100 10111000 10101101

  从上面的表格可以发现UTF-8编码一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

  谢谢清香白莲素还真的点评,强调一下,unicode是一种编码方式,和ascii是同一个概念,而UTF-8,UTF-16等是一种存储方式,在存储和传输上节约空间、提高性能的一种编码形式。

计算机系统通用的字符编码工作方式:

  在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。

  用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:

 

python_中文编码问题

  浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器:

python_中文编码问题

  

  所以很多网页的源码上会有类似<meta charset="UTF-8" />的信息,表示该网页正是用的UTF-8编码。


2.python2.7中的字符编码  

2.1 str 和 unicode

  python中有两种数据模型来支持字符串这种数据类型,str和unicode,它们的基类都是basestring。严格意义上说,str其实是字节串,它是unicode经过编码(例k如:unicode编码成utf-8、GBK等)后的字节组成的序列。在python中,str对象可以和unicode对象可以使用decode和encode函数相互转换。

 python_中文编码问题

  python中str对象和unicode的定义如下:

  1 #coding=utf-8
    2 str = "测试"     #str类型的字符串
    3 unStr=u"测试" #unicode类型的字符串:通过字符串前的u标识

                                                                           

2.2 decode()和encode()函数

  本小节的示例演示的操作系统环境均为linux下的console。

  2.2.1 decode函数:
  使用方法:unStr=str.decode(“dec_mode”),意即:按照dec_mode编码方式解析str对象,然后转换成unicode对象,当dec_mode与str对象本身的编码方式不吻合时,容易出现问题。示例源码charDecode.py 如下: 

    1 #coding=utf-8
    2 str = "测试"
    3 #unStr=str.decode("utf-8")
    4 unStr=str.decode("ascii")
    5 print type(str)    #打印str的类型
    6 print type(unStr)  #打印unStr的类型
    7 print repr(str)
    8 print repr(unStr)

  1)此时,以python charDecode.py运行该脚本,会提示如下错误:

  Traceback (most recent call last):
    File "charDecode.py", line 4, in <module>
      unStr=str.decode("ascii");
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)

  2)如果将上述代码中的第4行注释掉,第3行取消注释,再运行,就是正常的,结果如下:

  <type 'str'>
      <type 'unicode'>
  '\xe6\xb5\x8b\xe8\xaf\x95'
  u'\u6d4b\u8bd5'
  原因就是:代码中的str对象的编码方式是utf-8的(根据python的官方说明,sys.getdefaultencoding()函数,会返回str类型字符串的默认编码方式。本例中调用sys.getdefaultencoding(),返回结果为ascii,但是由于代码中的第1行中,声明了#coding=utf-8:意即指定代码文件中的对象的编码方式为utf-8,因此str的编码格式为utf-8),编码值为'\xe6\xb5\x8b\xe8\xaf\x95'。在1)中,当通过ascii方(取值0-127)解码str对象时,发现超出了127范围,当然就报错了; 而在2)中,str对象自身的编码方式和调用decode指定的编码方式是一致的,因此不会出现问题。

  一般遇到UnicodeDecodeError错误,首先检查调用decode时的指定的dec_mode是否和待解码str自身的编码方式是否一致。

  

  2.2.2 encode函数

  使用方法:str=unStr.encode(“enc_mode”),意即:按照enc_mode编码转换 unicode对象unStr,得到enc_mode编码格式的str对象。如果enc_mode与unStr不适配,那么也会出现问题(例如:unicode编码成ascii),这个问题会在下一章结合print语句,给出示例和解释。

  本章主要介绍了字符串编码和python中字符串的相关知识,下一章会分析一下python中print中文出现编码错误以及显示乱码的原因和解决方案。


在学习python以及在使用python进行项目开发的过程中,经常会使用print语句打印一些调试信息,这些调试信息中往往会包含中文,如果你使用python版本是python2.7,或许你也会遇到和我一样的问题:那就是print打印中文异常以及显示乱码问题。本文主要分析一下在linux下使用python2.7的print语句中文异常以及终端显示中文乱码问题的原因及解决办法。转载请注明出处,谢谢!

  1.print打印显示的过程

             python_中文编码问题

                                     图1. Print打印显示过程

  Python2.7中调用print打印var 变量时,操作系统会对var做一定的字符处理:如果var是str类型的变量,则直接将var变量交付给终端进行显示;如果var变量是unicode类型,则操作系统首先将var编码成str类型的对象(编码格式取决于stdout的编码格式),然后再交由终端进行显示。在终端显示时,如果str类型的变量的编码方式和终端设置的编码方式不一致,很可能会出现乱码问题。

  2.print中文字符出现错误问题

        在python源码中print中文字符,时常会出现Non-ASCII character和UnicodeEncodeError两类错误。下面分别一一介绍。

    2.1  Non-ASCII character错误

      print.py源码示例(代码1):

      import sys

      print sys.getdefaultencoding()

      a="测试"

      b=u"测试"

      print a

      print b

    这段代码试图在linux的终端打印变量a和b的值,但是在实际执行的过程中,会提示Non-ASCII character错误:

    python_中文编码问题

           原因:该print.py的文件格式是utf-8(可以vi print.py,然后在命令模式下,输入:set fileencoding,查看文件的编码方式,)。“测试”对应的utf-8编码为:'\xe6\xb5\x8b\xe8\xaf\x95',由于print.py中含有中文,且print.py没有指定编码方式,python会按照系统的默认编码解析执行print.py(这里的系统默认编码是ascii,查看系统的默认编码,可以调用sys.getdefaultencoing()函数),因此会提示Non-ASCII character的错误。

           解决办法:在print.py起始处,指定编码方式为utf-8,这样python在执行代码时,就知道要按照utf-8来解释执行代码了。代码2:

    #coding=utf-8

    import sys

    print sys.getdefaultencoding()

    a="测试"

    b=u"测试"

    print a

    print b

           运行结果如下:

           python_中文编码问题

    2.2 UnicodeEncodeError问题

                 代码2在192.168.86.61上能正常运行,但是换到另一台机器192.168.86.157就不能正常运行了,现象如下:

python_中文编码问题

             从打印信息来看,print a可以正常输出,而print b就会出现UnicodeEncodeError错误,这是为什么呢??

                 根据第1节中的介绍,变量b是unicode类型的,操作系统会按照stdout的默认编码将b编码成str类型的变量,根据报错信息猜测系统stdout的默认编码是ascii,而ascii字符的范围是0-127,因此会报上述错误。而变量a是str类型,调用print时,不需要经过操作系统进行编码,所以能正常输出。

                 那么,如何验证157上的系统stdout的编码方式是不是ascii呢?可以通过sys.stdout.encoding查看stdout的编码方式,这里的输出结果是ANSI_X3.4-1968,其别名就是ASCII,哈哈,原来真的是这样。

                 那么,为什么在192.168.86.61上,print b就能正常被打印输出呢?想要知道原因,让我们查看一下192.168.86.61上的stdout的编码方式,通过sys.stdout.encoding查得stdout的编码方式为utf-8,unicode类型的变量b的print时,首先被编码成utf-8,然后在送至终端显示,一切正常!

      至此,你可能明白了该问题产生的原因,那么,这个问题该怎么解决呢?一般建议在调用print打印变量时,首先调用encode()函数将unicode类型的变量进行编码,转换成str类型的变量,代码3如下:

      #coding=utf-8

      import sys

      print sys.getdefaultencoding()

      a="测试"

      b=u"测试"

      print a

      print b.encode('utf-8')

               之后,程序可以正常运行,如下:

             python_中文编码问题

                  

  3.linux终端显示中文乱码

   第1节中曾提到过:如果str类型的变量的编码方式和终端设置的编码方式不一致,在终端显示时就会出现中文乱码问题。笔者使用的终端的编码方式为utf-8,如下图:

                 python_中文编码问题

       如果将终端的编码方式改为GB2312,则中文就会出现乱码。因为b.encode('utf-8')的编码为utf-8,而终端的为GB2312,因此导致了乱码。

                python_中文编码问题

       解决方法就是要保持终端编码和待显示的变量的编码方式的一致。


https://www.cnblogs.com/litaozijin/p/6416133.html