当前位置: 首页 > news >正文

python3编码问题终结者--还搞不懂你来找我

python
unicode
bytes
str
编码

首先需要说明一下,该篇文章是以python3为基础的,python2是否适合没有验证过。
由于python编码问题确实比较多,文章篇幅可能较长,请耐心看完,绝对物超所值,何况还是免费的,只求转载的时候注明出处,谢谢!

一、 简单的编码介绍

平常我们可能听说过很多编码格式,如 ASCII码,Unicode,utf-8,gbk等等。为了不让文章臃肿,所以在这不再赘述,如想了解,请跳转到这个链接。
各种字符编码介绍

但是py3里,只有 unicode编码格式 的字节串才能叫作str。
其他编码格式的统统都叫bytes,如:gbk,utf-8,gb2312…………

在py3中,Unicode编码就像是一个枢纽,例如gbk的格式要想转化成utf-8,那么必须先转化成Unicode,然后再从Unicode转化成utf-8。

python3编码问题终结者--还搞不懂你来找我 - marsggbo - 火星教教主-marsggbo
 

编码格式转换.png

二、老大难的文件操作

python各种各样的扩展卡确实给我们带来了极大的方便,但是对于初学者而言,编码问题却一而再再而三的出现,尤其以文件操作最为明显(反正我是这样的)
接下来将主要介绍文件读写操作和文件编码方式检测的方法。

  • 文件读写:open还是 codecs.open?

python读写文件估计大家都用open内置函数,但是用open方法打开会有一些问题。open打开文件只能写入str类型,不管字符串是什么编码方式。例如

  1. >>> fr = open('test.txt','a'
  2. >>> line1 = "我爱祖国" 
  3. >>> fr.write(line1) 

这样是完全可以的。但是有时候我们爬虫或者其他方式得到一些数据写入文件时会有编码不统一的问题,所以就一般都统一转换为unicode。此时写入open方式打开的文件就有问题了。例如

  1.  
  2. >>> line2 = u'我爱祖国' 
  3. >>> fr.write(line2) 
  4.  
  5. Traceback (most recent call last): 
  6. File "<pyshell#4>", line 1, in <module> 
  7. fr.write(line2) 
  8. UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-11: ordinal not in range(128) 
  9. >>> 

怎么办,我们可以将上面的line2编码成str类型,但是太麻烦。我们要把得到的东西先decode为unicode再encode为str。。。
input文件(gbk, utf-8...) ----decode-----> unicode -------encode------> output文件(gbk, utf-8...)

代替这繁琐的操作就是codecs.open,例如

  1. >>> import codecs 
  2. >>> fw = codecs.open('test1.txt','a','utf-8'
  3. >>> fw.write(line2) 
  4. >>> 

不会报错,说明写入成功。这种方法可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数 是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述 操作。相对内置的open()来说,这个方法比较不容易在编码上出现问题。

  • 还是文件读写操作

上文中介绍的codecs.open()方法虽然明显比open要方便好用很多,但是使用这个函数的前提是我们需要知道文件的编码方式,但是事实是我们大多数情况下不知道文件的编码方式,所以一下给出两种解决办法。

  • 1.最原始的方法。。。

  1. ways = ["utf-8","gbk","gb2312","ASCII","Unicode"
  2. for encoding in ways: 
  3. print(encoding) 
  4. try
  5. with codecs.open("test.csv","r",encoding=encoding) as f: 
  6. data = f.read() 
  7. print(type(data)) 
  8. break 
  9. except Exception as e: 
  10. pass 

将python中常用的编码方式用list表示,然后用for循环逐一带入检验。由于utf-8和gbk用的较多,所以建议放在list的最前面。
一旦文件操作成功,则break,跳出循环。

  • 2.比较高端的方法

可以以bytes的形式对文件进行操作,这样即使不知道文件的编码方式也同样可以进行读写操作了,但是在最后需要进行decode或者encode。
如果对decode和encode不了解,请阅读这篇文章python编码问题之"encode"&"decode"

  1. with codecs.open("test.csv","rb") as f: 
  2. data = f.read() 
  3. print(type(data)) 
  4. encodeInfo = chardet.detect(data) 
  5. print(data.decode(encodeInfo["encoding"])) 

亲测得到的结果如下图

python3编码问题终结者--还搞不懂你来找我 - marsggbo - 火星教教主-marsggbo
 


4.png

解释一下上面的代码中的chardet.detect()
chardet是一个python3自带的库,用于检测文本的编码方式,他会返回一个字典,格式是{"encoding" : "xxx", "confidence" :" xxx"}但是注意它一般只能检测bytes类型的编码格式,比如

  1. import chardet  
  2.  
  3. a = "你好" 
  4. print(type(a)) 
  5. chardet.detect(a) 
  6.  
  7. >>> 
  8. <class 'str'> 
  9. Traceback (most recent call last): 
  10. File "E:\Code\python\Flask\csv-mysql\test.py", line 63, in <module> 
  11. chardet.detect(a) 
  12. File "C:\Python35\lib\site-packages\chardet\__init__.py", line 25, in detect 
  13. raise ValueError('Expected a bytes object, not a unicode object'
  14. ValueError: Expected a bytes object, not a unicode object 

总结一下:
本文一方面简单介绍了python的编码情况,另一方面介绍了文件操作中会遇到了问题以及解决的办法。

提出的建议是

使用codecs.open()打开文件

使用bytes方式访问文件,如rb和wb

使用chardet.detect()检测bytes类型文本的编码格式,然后再解码(decode)或者编码(encode)


End


相关文章:

  • Python(三)之Python的表达式和语句概述
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • 消息中间件简介
  • 画像分析(4-1)智能搬迁和数据订阅
  • Bzoj4771 七彩树
  • Oracle 数据库备份脚本
  • C8051F340 USB Fn hacking
  • Android Studio 开始运行错误
  • 对象——浅识
  • Hadoop单机版快速搭建及测试
  • Android开源项目规范总结
  • PHP 使用 Redis
  • MySQL 高可用性—keepalived+mysql双主(有详细步骤和全部配置项解释)
  • Visual Studio 版本管理从TFS迁移到SVN
  • write-ahead-log与append-only-file的原理
  • Android 架构优化~MVP 架构改造
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • github从入门到放弃(1)
  • IndexedDB
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • Js基础——数据类型之Null和Undefined
  • Linux链接文件
  • oldjun 检测网站的经验
  • Python 基础起步 (十) 什么叫函数?
  • React Native移动开发实战-3-实现页面间的数据传递
  • Redis 懒删除(lazy free)简史
  • spark本地环境的搭建到运行第一个spark程序
  • spring学习第二天
  • VuePress 静态网站生成
  • 如何设计一个微型分布式架构?
  • 如何实现 font-size 的响应式
  • 通过git安装npm私有模块
  • 智能合约开发环境搭建及Hello World合约
  • ​linux启动进程的方式
  • #微信小程序(布局、渲染层基础知识)
  • #微信小程序:微信小程序常见的配置传旨
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (floyd+补集) poj 3275
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (补)B+树一些思想
  • (一)Java算法:二分查找
  • .axf 转化 .bin文件 的方法
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET4.0并行计算技术基础(1)
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .pyc文件是什么?
  • /bin、/sbin、/usr/bin、/usr/sbin
  • @EnableWebMvc介绍和使用详细demo
  • @Import注解详解
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决
  • []error LNK2001: unresolved external symbol _m
  • []串口通信 零星笔记
  • [1]-基于图搜索的路径规划基础
  • [2015][note]基于薄向列液晶层的可调谐THz fishnet超材料快速开关——
  • [AIGC 大数据基础]hive浅谈