python中字符串输出乱码怎么解决,彻底搞懂 python 中文乱码问题

  python中字符串输出乱码怎么解决,彻底搞懂 python 中文乱码问题

  Python序言中的中文乱码困扰了我很多年。每次出现中文乱码,都要上网搜答案。解决了当时遇到的问题,但是下次有乱码就会变得懵懂。如果追究原因,我们还是不知道原因。现在,一些合作伙伴的代码中不使用中文,以避免中文乱码的问题。评论和提示都是英文的。我也这么做了。但是,这不是解决问题,而是回避问题。今天我们一起来解决Python的中文乱码问题。

  基础知识在ASCII之前,为了表示世界上的一切,有人决定将8个可以切换到不同状态的晶体管组合在一起。他们看到这8个开关状态良好,他们称之为“字节”。后来,他们制造了另一种可以处理这些字节的机器。机器启动了,很多状态都是用字节组合的,状态开始变化。他们看了觉得很好,就把这台机器叫做“电脑”。电脑只在美国使用。8位字节可以组合256种不同的状态(2的8次方)。它们将数字从0开始的32种状态定义为特殊用途,但是终端和打印机在接收到约定的字节时必须执行约定的动作。遇到010,终端变线,遇到007,终端哔哔叫人。例如,当遇到0x1b时,打印机打印翻转的文本,终端显示彩色文本。他们一看不错,就把这些020以下的字节状态叫做“控制码”。他们还用连续的字节来表示所有的空格、标点符号、数字、大小写,并编辑成127,以便计算机可以用不同的字节存储英文字符。大家看到这个都觉得很不错,于是把这个方案叫做ANSI(美国信息交换标准代码)的“Ascii”码。当时,世界上所有的计算机都使用相同的ASCII程序来存储英文字符。

  GB2312后来,全世界的人都开始使用电脑,就像建造巴别塔一样。然而,许多国家都不使用英语。他们的字母表里有很多东西是ASCII所没有的。为了在计算机中存储他们的字符,他们决定用127号后的空格来表示这些新的字符和符号。此外,还增加了很多绘制表格时必须使用的横线、竖线、十字等形式,并编号到最后。从128页到255页的字符集称为“扩展字符集”。从此,贪婪的人类再也无法在新的条件下使用计算机。美帝国主义可能没有想到,第三世界国家的人愿意使用电脑。中国人有了电脑,就没有更多的字节态可以用来表示汉字了。此外,还需要保存6000多个常用汉字。

  然而,这是一个无法形容的中国人。我们毫不客气地取消了127号后面的奇怪符号,虽然小于127的字和以前的意思一样,但是大于127的两个字,连在一起,就代表汉字了。后面的第一个字节(他是高位字节)从0xA1到000字节。这些代码也有内置的数学符号,罗马和希腊字母。ASCII码中的原始数字、标点符号和字母的长度为2个字节。这就是所谓的“全角”字,127号以下的原字称为“半角”字。国内的人觉得这个很好,就把这个汉字方案叫做“GB2312”。GB2312是ASCII的中文扩展。

  虽然是在GBK,但我很快发现中国的汉字太多了,很多人的名字在这里都打不出来。也有让别人特别头疼的国家领导人。所以一定要找出GB2312中没有使用的码位,老老实实的使用。之后就不够了,不再要求低位字节必须是127号之后的内码,只要第一个字节大于127,不管字符集的内容是否扩展,都会固定表示这是汉字的开头。由此,扩展后的编码方案被称为GBK标准,GBK包含了GB2312的全部内容,同时增加了近2万个新的汉字(包括繁体字)和符号。后来,少数民族开始使用电脑。我们进一步扩充并增加了数千个新的种族角色。GBK扩展到GB18030。

  从此,中华民族文化在电脑时代得以传承。国内的程序员看到这个系列的汉字编码有一个很好的标准,俗称“DBCS”(Double Byte Charecterset双字节字符集)。根据DBCS系列标准,最大的特点是双字节汉字和单字节英文字符共存于同一编码体系中。所以他们写的程序一定要注意字符串中每个字节的值,以支持中央处理。如果该值大于127,可能会出现双字节字符集字符。那时候有福可编程计算机qcdqj一天要背几百遍下一个咒语。“一个汉字带两个英文字母!一个汉字带两个英文字母……”

  当时各国都和中国一样,制定了自己的编码标准,所以互不知道对方的编码,也没有人支持别人的编码。即使相距仅150海里、使用同一种语言的mainland China和台湾省,也采用不同的DBCS编码方案。3354年,中国人想在电脑上显示汉字,就需要安装“汉字系统”。虽然是用来处理汉字的表示和输入的,但是台湾省愚蠢的封建人士写的占卜师,必须再配一个支持BIG5码的“立天汉字系统”才能使用。如果书写系统错误,显示会非常混乱。这个呢?而且,在世界各国的森林里,都有一些暂时用不上电脑的穷人。他们的话呢?多么不切实际的提议。

  大学

  就在这时,大天使加百列及时出现了,一个叫ISO的国际组织决定解决这个问题。他们采用的方法很简单:废除所有地域编码方案,重新创造一个包含地球上所有文化、字母和符号的编码!他们准备称之为“通用多八位编码字符集”,简称UCS,俗称“unicode”。unicode刚制定出来的时候,计算机的内存容量有了很大的发展,空间不再是问题。所以ISO直接规定必须用两个字节也就是16位来统一表示所有字符。对于ASCII中的那些“半角”字符,unicode保持原来的编码不变,只是将长度从原来的8位扩展到16位,而其他文化和语言的所有字符都重新编码。

  由于“半角”的英文符号只需要使用低8位,其高8位始终为0,所以这种大气的方案在保存英文文本时会浪费两倍的空间。这个时候,从旧社会过来的程序员开始发现一个奇怪的现象:他们的strlen函数不靠谱,一个汉字不再等同于两个字,而是一个!是的,从unicode开始,无论是半角英文字母还是全角汉字都是统一的“一字”!同时都是统一的“两个字节”。请注意术语“字符”和“字节”之间的区别。字节是8位的物理存储单位,而字符是与文化相关的符号。在unicode中,一个字符是两个字节。一个汉字算两个英文字的时代快结束了。

  Unicode也不是完美的。这里有两个问题。一个是,我们如何区分unicode和ASCII?计算机怎么知道三个字节分别代表一个符号而不是三个符号?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了。如果unicode统一规定每个符号用三个或四个字节表示,那么每个英文字母前的两三个字节必须是0,这是对存储空间的极大浪费,文本文件的大小也会大两三倍,这是不可接受的。

  UTF-8 unicode在很长一段时间内都无法普及,直到互联网的出现。为了解决unicode如何在互联网上传输的问题,出现了许多用于传输的UTF(UCS传输格式)标准。顾名思义,UTF-8是每次传输8比特的数据,而UTF-16是每次传输16比特的数据。UTF-8是互联网上使用最广泛的unicode实现之一。它是一种为传输而设计的代码,使代码无国界,从而可以显示世界上所有文化的字符。UTF-8最大的特点之一是它是一种可变长度的编码方法。它可以用1~4个字节来表示一个符号,字节长度根据符号的不同而不同。当一个字符在ASCII码的范围内时,它用一个字节来表示,ASCII字符的一个字节的编码被保留作为它的一部分。注意,unicode中的一个汉字占2个字节,而UTF-8中的一个汉字占3个字节)。Unicode到uft-8不是直接对应,而是要通过一些算法和规则进行转换。

  在这里,如果你看到自己是完全不知所措还是豁然开朗,我建议你多看几遍,前车之鉴,后车之鉴。如果突然天亮了,我们就继续往下看。

  解释完中文乱码例子的基础知识,再来说说Python中字符是如何存储的。我们先来看一个乱码的例子。创建一个新的demo.py文件,该文件以utf-8格式存储。文件中的内容如下。

  S=中文 print s在cmd中运行python demo.py,什么?我只想用中文打印两个字,但它给我一个错误。真是难以置信!

  赶紧试试打开python自己的闲置。一点问题都没有。为什么?

  回头好好看看文件demo.py第1行cmd-非ascii字符 \ xe4 报错,但是没有声明编码;翻译过来就是在 demo.py 文件的第 1 行有非 ASCII 字符 ‘\xe4’,而且没有声明编码。从以上基础知识来看,ASCII码不能代表汉字中文。demo.py文件的第一行有两个汉字中文,而demo.py文件的存储格式是utf-8,所以这两个汉字中文在存储到文件中时是以utf-8编码存储的。查看demo.py文件的十六进制,可以看到中文存储\xe4\xb8\xad\xe6\x96\x87。

  记事本提供的HEX-Editor插件用于十六进制查看,函数repr也可以显示原字符串,如下。

  # encoding:utf-8 import sysprintsys . getdefaultencoding()s=中文打印报告

  Sys.getdefaultencoding()以ascii为默认编码读取python,但是ASCII不知道\xe4,所以会在filedemo.py online1中报错非ASCII字符 \ xe4 ,但是没有声明编码;此时,只需在demo.py文件的文件头添加# encoding:utf-8即可。虽然是注释,但是python看到这句话后知道接下来应该是utf-8编码,而demo.py存储时也是utf-8,所以很正常。

  #编码:utf-8s=中文 print s .也可以写成#-*-编码:utf-8-*-只要正则表达式[\ t \ v] * #。*?编码[:=][ \t]*([-_。a-zA-Z0-9])就可以了。

  让我们再次尝试在cmd下运行python demo.py。

  什么,什么,什么,说好的展示中文呢?这不是开玩笑吗?试试python idle。

  为什么python中同样的文件正常是空闲的?cmd肯定有问题。是的,我也这么认为。然后我会尝试进入python交互模式,在cmd下输出中文。我即使在cmd下也能正常输出中文。看到这里我相信朋友们都晕了。

  别急,让我慢慢分析。其实在cmd或者idle打印字符的时候,和文件编码方式无关。这时候起作用的是输出环境,也就是cmd或者idle的编码方式。检查cmd的编码命令是chcp,返回936。上网查一下936代表GBK编码。现在我们大概知道原因了。demo.py的文件存储和编码声明都是utf-8,但是cmd显示编码是GBK,如果把中文utf-8编码\ X4 \ Xb8 \ XAD \ X6 \ X96 \ X87强行转换成GBK就会乱码。GBK用两个字节存储一个汉字,所以\ X4 \ Xb8 \ XAD \为什么可以在cmd下进入python交互命令行?这是因为当你在Python交互命令行输入s= Chinese 时,这两个汉字实际上是以GBK码存储的,而cmd的默认代码是GBK。不信你看S print \xd6\xd0\xce\xc4,是GBK码存储的,而utf-8码存储的中文和\ xe4 \ xb一样。下面告诉大家如何解决在cmd下执行文件才能正确输出中文的问题。

  1.demo.py文件和编码语句都是GBK。这个方法比较蠢,就是把demo.py文件改成GBK存储,编码语句也是GBK,个人不推荐。

  # encoding:gbks= Chinese print sprint代表

  2.中文是unicode的,也就是说只要在中文前面加一个笑耳机标记,后面的中文就会用unicode存储。

  # encoding:utf-8s=u Chinese print sprint repr(s)cmd可以打印unicode字符,如下所示。

  3.强制将中文转换成gbk或unicode代码转换成unicode代码。在Python中,代码可以相互转换,比如utf-8到GBK。不同代码不能直接转换,需要经过unicode字符集的中间过渡。从上面的基础知识可以知道,unicode是字符集,不属于代码,而utf-8是具体实现unicode思想的代码。Utf-8转unicode是一个解码过程,可以通过decode从utf-8解码成unicode。

  # encoding:utf-8s= Chinese u=s . decode( utf-8 )print u print type(u)print rep(u)

  强制转换为gbk编码,上一步已经从utf-8转换为unicode。unicode是编码的过程,通过encode实现。

  # encoding:utf-8s= Chinese u=s . decode( utf-8 )g=u . encode( gbk )print g打印类型(g) print repr (g)

  总结

  windows cmd窗口不支持Utf-8。如果要显示中文,必须转换成gbk或者unicode,Python idle支持这三种编码。中文乱码都是编码不一致造成的。utf-8用于存储,gbk用于打印会出现乱码。所以要保证乱码尽量不要保持统一。建议对所有代码使用unicode。

  Decode解码叫从其他码解码成unicode,解码方法是decode。第一个参数是解码后的字符串的原始编码格式,如果写错了会报错。比如s是utf-8,用gbk解码会出错。

  # encoding:utf-8s=中文 u=s . decode( GBK )print u print rep(u)

  小提示

  在Python idle和cmd下直接输入s= Chinese 会用gbk编码。如果在一个文件中输入s= Chinese ,文件存储格式是utf-8,那么s是用utf-8编码存储的,这就有点不一样了。你踩到坑了,文件运行成功Python idle可能会失败。

  Encode编码不能直接从utf-8转换成gbk,必须用unicode转换,这一点很重要。要编码的原始字符串必须是unicode,否则将会报告错误。

  Raw_input raw_input用于获取用户输入值,获取的用户输入值与当前运行环境代码相关。例如,如果cmd下的默认编码是gbk,那么输入的汉字就用gbk编码,不管demo.py文件编码格式和编码语句是什么。

  # encoding:utf-8s=raw _ input( input something:)打印sprint类型打印repr

  GBK编码一个汉字的两个字节,而UTF 8编码一个汉字的三个字节。

  细心的朋友注意到了,raw_input的提示是英文的,如果改成中文,真的有乱码。

  # encoding:utf-8s=raw_input(请输入汉字:)print sprint type(s)print repr(s)

  我该怎么办?只需强制提示字符串为gbk编码,但不允许unicode和utf-8。

  # encoding:utf-8s=raw_input(u 请输入汉字:。encode( gbk ))print sprint type print repr

  equal trap“中文”的两个字符串存储在不同的代码中,utf-8代码和gbk代码存储的“中文”是不同的。

  一口气说了这么多,不知道你看懂了吗?如果你想避免乱码,只要记住以下五条规则。

  该文件以utf-8格式存储,编码声明为utf-8。#编码:utf-8汉字出现的地方前面都是U,不同编码之间不能直接转换。unicode中间跳转cmd下不支持utf-8编码,raw_input提示字符串只能用gbk编码。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: