处理Python2.7的中文乱码问题

Python2.7对于中文编码的问题处理的并不好,在此做一个简单的整理总结。
Python 3 中字符均使用unicode编码,unicode函数不再需要。

原理

关于编码格式

  • gbk是win环境下的一种汉字编码,其中GB2312编码也算是gbk编码
  • utf-8是Unix下的一种通用编码,可以对汉字编码
  • unicode是一种二进制编码,所有的utf-8和gbk编码都得通过unicode编码进行转译,说的直白一点,utf-8和gbk编码之间不能之间转换,要在unicode之间过个场才能转换。

程序存储、传输、操作字符串时,对代码中写好的字符串或者手动输入的字符串,程序会自动将这些字符串按照某种字符集编码(一般为本地系统字符编码)将字符串转换为字节码,这是字符的“解码”,将显示的字符转化为字节码;
程序中显示文字时,计算机读取一串字节,选择合适的字符集(一般为本地系统字符集)将字节码翻译为字符集中对应的字符,这些字符一般为本地存储的字符图片,然后调用系统的显示接口将这些“图片”打印在屏幕上。这是字符的“编码”,将字节码转化为可显示的字符。
如果字符的解码和编码采用的是相同的字符集,则将显示出来原始给定的字符,结果正常;如果不是同一种字符集,则有可能会出现乱码(因为相同的字节码在不同的字符集中可能对应不同的字符,一种字符集的某字符解码后的字节码在另一种字符集中编码之后可能是不同的字符)。
为了方便的处理不同字符集编码的字符之间的相互转化,定义了unicode标准,即将世界上所有的字符统一起来,每个字符都分配一个唯一的id,作为该字符的unicode码值。在代码中写定字符或者程序输入字符后,可以先将字符转化为unicode”字符”,这是“解码”过程;进行一系列操作之后,如果需要显示出原来的字符,则将unicode”字符”转化为对应的字符集中该字符所对应的字节码,然后找到对应的字符,进而显示。这样,不同字符集编码就通过unicode”字符”联系了起来。

pyhton的所有内置库、方法接受的是unicode编码的字符串。
Linux平台编码(UTF-8)与Window平台(GBK),win的命令返回的是GBK编码。

如何查看文档、字符串编码格式

# coding:utf-8  

import chardet  
s = '哈哈哈我就是一段测试的汉字呀'  
print chardet.detect(s)

# 输出:{'confidence': 0.99, 'encoding': 'utf-8'}


isinstance(s, unicode)      # 用来判断是否为unicode

import sys
print sys.getdefaultencoding()  # 获得系统的默认编码

这个办法只能输出这段字符可能的编码格式,我们看到0.99的可能是utf-8,其实也就是utf-8编码了,只要字符串够长,后面的置信度都是0.99

各种编码之间如何转换

Python提供了两个函数 decode() 和 encode()

# encoding: utf-8

decode('utf-8')     # 是从utf-8编码转换成unicode编码
encode('gbk')       # 是将unicode编码编译成gbk编码
str.decode('utf-8').encode('gbk')   # 将已知是utf-8的字符串str转成gbk格式编码


#直接定义unicode字符串,通过在字符串前加 u 的方式
unicodestring = u"Hello world" 

#py文件的开头写了 #encoding=utf-8,在整个py文件中,所有的字符串的编码编码方式都设置为utf-8
utf8string = '这样直接写,字符串编码方式是utf-8' 

#将某种字符集编码的字符串转化为unicode字符串, 即“解码”
ustring = unicode(utf8string, "utf-8")
ustring                 # 输出 u'\u597d\u4eba'
print type(ustring)     # 输出 <type 'unicode'>

print ustring.encode('utf-8')   # 输出正常,解码到unicode和从unicode编码的字符集相同
print ustring.encode('gbk')     # 输出乱码,解码到unicode和从unicode编码的字符集不同

#如果一个字符串已经是unicode了,再进行解码则将出错,因此通常要对其编码方式是否为unicode进行判断
isinstance(s, unicode)      # 用来判断是否为unicode

注意:转码出现错误时,分析原来的编码格式是什么,先通过decode解码成unicode,再通过encode编码成指定格式。
如果一个字符串已经是unicode了,再进行解码则将出错;而用非unicode编码形式的str来encode会报错

应用

1.设置默认编码

在代码的首行添加相应说明,设置默认utf-8编码格式,可以解决一般情况下的中文报错。当然,编程中遇到具体问题还需具体分析啦。

# encoding: utf-8
# -*- coding: utf-8 -*-
import sys  
default_encoding = 'utf-8'
if sys.getdefaultencoding() != default_encoding:
   reload(sys)
   sys.setdefaultencoding(default_encoding)

2.文件读写

文件读写中遇到中文,通常不会报错,但是最后运行结果显示乱码,给后续处理带来不便。

2.1 读文件

方式一
pyhton的所有内置库、方法接受的是unicode编码的字符串。
读文件时,如果文件路径、文件名中有中文,需要使用unicode函数将其从’utf-8’格式解码为unicode,然后再进行正常的文件读取。
以pandas的read_csv函数为例,使用如下代码可以成功地读取名为“POI总表”的csv文件,保存在DataFrame数据类型的poi_list。

import pandas as pd
inpath = 'C:\\POI总表.csv'
path = unicode(inpath, 'utf-8')
poi_list = pd.read_csv(path)

方式二
通过xlrd读取Excel文件时,文件名src_excel_path包含中文字符,可以通过指定xlrd.open_workbook的参数encoding_override编码为’utf-8’

excel_data_src = xlrd.open_workbook(src_excel_path, encoding_override = 'utf-8')
excel_sheet = excel_data_src.sheet_by_index(0)


2.2 写文件

  1. 文件名有中文,文件名乱码
    当想要将程序运行结果保存到文本文件时,文本文件的命名中如果有中文,不做处理文件名会出现乱码。利用unicode函数进行解码可解。unicode(‘中文.csv’,’utf-8’)
  2. 文件内容有中文,打开内容乱码

方式一
使用codecs包在创建文件后添加语句f.write(codecs.BOM_UTF8)
优点:简单粗暴,后续write不用特殊处理
缺点:写入文件编码格式是带BOM的utf-8

import codecs
f = open(unicode(name+'.csv','utf-8'),'w')  # 文件名不乱码
f.write(codecs.BOM_UTF8)  # 设置编码格式为带BOM的utf-8
f.write('123,语文')
f.close()

方式二
pyhton的所有内置库、方法接受的是unicode编码的字符串。
每次写入内容,利用unicode函数进行解码,write(unicode(‘写入内容’,’utf-8’))

lua_export_file = open(unicode(pathlua,'utf-8'),'w')  # 文件名不乱码
lua_export_file.write(unicode('local data = {}','utf-8'))
lua_export_file.write(unicode(metatable_format_desc % lua_table_name,'utf-8'))
# head_desc是从win程序输入获取的,是gbk格式,需要先解码后编码utf-8
lua_export_file.write(head_desc.decode('gbk').encode('utf8')) 
lua_export_file.close()



参考文档:
处理Python2.7读写文件中的中文乱码问题
作者:haha_point

Python对中文字符的处理(utf-8/ gbk/ unicode)
作者:chixujohnny

python unicode字符串
作者:媛媛_sophie

猜你喜欢

转载自blog.csdn.net/crayon_chen/article/details/80757481