網(wǎng)站首頁 編程語言 正文
今天真的被編碼問題一直困擾著,午休都沒進(jìn)行。也真的見識(shí)到了各種編碼。例如:gbk,unicode、utf-8、ansi、gb2312等。
如果腳本程序中編碼與文件編碼不一致,就會(huì)報(bào)出UnicodedecodeError的錯(cuò)誤。
1.情景一
讀文件時(shí)常需要將內(nèi)容轉(zhuǎn)為utf8,文字可正常顯示,但是如果原文件內(nèi)容編碼格式不是utf8就會(huì)報(bào)錯(cuò)UnicodedecodeError。如下:
問題:
try:
fileObj = open(os.path.join(path,filename),'r')
textLines = fileObj.readlines()
fileObj.close()
except IOError as err:
print('打開文件%s失敗:%s'%(filename,err))
解決方法:
代碼改為:
try:
fileObj = open(os.path.join(path,filename),'r',encoding='utf-8')
textLines = fileObj.readlines()
fileObj.close()
except IOError as err:
print('打開文件%s失敗:%s'%(filename,err))
此方法可以解決一部分編碼問題,但是卻不是一勞永逸的,在下一批文件因其他功能擴(kuò)展需要讀寫時(shí),上面程序又報(bào)出UnicodedecodeError:gbk codec cant decode…
2.情景二
針對(duì)上面的編碼問題沒有得到很好的解決,決定專門寫一個(gè)批量將文件夾下面的文件編碼格式改為utf-8的腳本,網(wǎng)上查資料得知python的第三方模塊chardet,但是要安裝這個(gè)擴(kuò)展庫。
chardet是一個(gè)非常好的編碼識(shí)別模塊,
1.chardet庫的安裝
在外網(wǎng)機(jī)上安裝這個(gè)模塊是特表簡單的,直接執(zhí)行pip chardet install命令即可,但是我的工作環(huán)境是內(nèi)網(wǎng),因?yàn)檫@個(gè)項(xiàng)目要處理的文件量多且大,所以也在Windows系統(tǒng)(編碼問題比Linux多),因此安裝chardet模塊也花費(fèi)了好大一會(huì)時(shí)間。
a.在外網(wǎng)下載好安裝包c(diǎn)hardet-3.0.4.tar.gz。
b.解壓縮放在python安裝路徑\Python\Lib\site-packages下,命令切換到當(dāng)前目錄,執(zhí)行python setup.py install。
c.安裝完畢后import chardet仍然未成功
上面的安裝步驟是沒有問題的,我想應(yīng)該是因?yàn)槟硞€(gè)依賴沒有安裝吧,因此突然想到一個(gè)比較笨的方法:就是在外網(wǎng)機(jī)上執(zhí)行pip chardet install先安裝好,然后到安裝目錄下把關(guān)于chardet的安裝目錄chardet和chardet-3.0.4.dist-info拷貝到內(nèi)網(wǎng)機(jī)\Python\Lib\site-packages下,再import chardet時(shí)竟然成功了。。。。
編寫文件編碼格式轉(zhuǎn)換腳本
#!/usr/bin/python
# _*_ coding:utf-8 _*_
#更改文件編碼,文件統(tǒng)一改為utf-8無BOM格式
import os
from chardet import detect
#文件夾目錄
g_filedir = r'C:\Users\Desktop\nmg\SS'
def runcoding(path):
for filename in os.listdir(path):
if filename.endswith('.txt'):
with open(os.path.join(path,filename),'rb+') as fileObj:
fileContent = fileObj.read()
#判斷編碼格式
encodingtype = detect(fileContent)['encoding']
print(encodingtype)
#格式轉(zhuǎn)換
fileContent = fileContent.decode(encodingtype).encode('utf8')
#寫回文件
fileObj.seek(0)
fileObj.write(fileContent)
if __name__=="__main__":
runcoding(g_filedir)
在處理字符串時(shí),常常會(huì)遇到不知道字符串是何種編碼,如果不知道字符串的編碼就不能將字符串轉(zhuǎn)換成需要的編碼。上面的chardet模塊就能很好的解決這個(gè)問題。
此時(shí)當(dāng)前文件夾下的文件順利的進(jìn)行了讀寫,再次readlines時(shí)沒有報(bào)UnicodedecodeError問題。可以檢測到gbk、Unicode、utf8、utf16、utf8(big)等編碼,也不用再一個(gè)編碼一個(gè)編碼的去轉(zhuǎn)換,一個(gè)文件一個(gè)文件的轉(zhuǎn)換。以為編碼問題終于一次性解決了。
但是。。。到另一個(gè)省份的一批文件要進(jìn)行批量操作時(shí),進(jìn)行到第49個(gè)文件就終止了,又報(bào)出UnicodedecodeError:‘utf8’ codec cant decode問題。。。。用上面腳本對(duì)該省份文件夾下文件進(jìn)行格式轉(zhuǎn)換時(shí)報(bào)出錯(cuò)誤:TypeError:decode() argument 1 must be str ,not None。
3.情景三
針對(duì)情景2的問題,仍要繼續(xù)排查編碼的問題,根據(jù)運(yùn)行的情景二的腳本時(shí)報(bào)出的錯(cuò)誤在腳本中添加代碼,打印出返回None的文件名。
修正代碼
#!/usr/bin/python
# _*_ coding:utf-8 _*_
#更改文件編碼,文件統(tǒng)一改為utf-8無BOM格式
import os
from chardet import detect
#文件夾目錄
g_filedir = r'C:\Users\Desktop\nmg\SS'
def runcoding(path):
for filename in os.listdir(path):
if filename.endswith('.txt'):
with open(os.path.join(path,filename),'rb+') as fileObj:
fileContent = fileObj.read()
#判斷編碼格式
encodingtype = detect(fileContent)['encoding']
#ansi編碼檢測結(jié)果為none
if encodingtype==None:
print(filename)
continue
#print(encodingtype)
#格式轉(zhuǎn)換
fileContent = fileContent.decode(encodingtype).encode('utf8')
#寫回文件
fileObj.seek(0)
fileObj.write(fileContent)
if __name__=="__main__":
runcoding(g_filedir)
然后定位到那個(gè)文件,記事本打開再另存為查看編碼方式為ANSI,或者使用notpad++查看編碼類型。
記事本默認(rèn)是以ANSI編碼保存文本文檔的,而正是這種編碼存在的bug招致了上述怪現(xiàn)象。假如保存時(shí)選擇Unicode、Unicode (Big Endian)、UTF-8編碼,就正常了。此外,假如以ANSI編碼保存含有某些特別符號(hào)的文本文檔,再次打開后符號(hào)也會(huì)變成英文問號(hào)。
這里可以得知,文件以ansi編碼時(shí)decode()函數(shù)返回的事None。
4. chardet模塊detect()函數(shù)
chardet模塊中的chardet.detect()函數(shù)可以檢測編碼。返回結(jié)果如下:
data = '我最美'.encode('gbk')
chardet.detect(data)
Out[103]: {'confidence': 0.73, 'encoding': 'ISO-8859-1', 'language': ''}
輸出結(jié)果confidence為概率。
encoding為字符串的編碼方式。
編碼問題最困擾人,好在今天順利解決了,各個(gè)省份的數(shù)據(jù)也都按照格式要求修改完畢,已經(jīng)上報(bào)到各省份,晚上就花點(diǎn)時(shí)間整理以下嘍。
原文鏈接:https://blog.csdn.net/w1418899532/article/details/84308049
相關(guān)推薦
- 2022-11-13 python學(xué)習(xí)之whl文件解釋與安裝詳解_python
- 2022-04-07 C++11生成隨機(jī)數(shù)(random庫)的使用_C 語言
- 2022-02-06 TP6記錄報(bào)錯(cuò)的SQL語句
- 2023-11-11 Jetson nano 安裝swapfile 解決Cannot allocate memory 問題
- 2022-11-19 C#字符串與正則表達(dá)式的圖文詳解_C#教程
- 2022-06-04 C#處理類型和二進(jìn)制數(shù)據(jù)轉(zhuǎn)換并提高程序性能_C#教程
- 2022-07-09 使用Jquery操作Cookies_jquery
- 2022-11-27 Docker?容器互聯(lián)互通的實(shí)現(xiàn)方法_docker
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支