目錄
都是編碼的問題
不管是什麼樣的程式語言,當匯出檔案的時候,編碼都是一個讓人頭痛的問題。經常發生的情況是,你匯出了一個csv檔,在你的電腦上完全可以正常顯示,但傳給同事後,他卻回覆說打開全部都是亂碼,並表達出一種「你怎麼都沒有好好檢查」的微妙情緒。
編碼問題之所以麻煩,因為它可能牽涉到作業系統的設定、檔案格式、編碼格式等問題。就算我能夠順利匯出正確的檔案,實際上我不清楚系統的背後發生了什麼事,但也不覺得有弄懂它的必要,只要知道哪個方法可行就可以了,相信你和我一樣也不在乎。
針對Python的編碼問題,我會分成三個部份:
- 檔案格式:包括csv和xlsx兩種格式。
- 編碼:包括utf-8、utf-8-sig、big5等。
- Python模組:最常見的模組是pandas,但也可以使用csv。這篇文章不會特別討論,因為pandas看起來是把csv寫在模組裡面。
給同事的緊急自救手冊
在正式開始之前,我們先提供一個緊急應變方法:如果你匯出的檔案是csv,而你的同事看到的是亂碥,可以請他不要雙擊開啟檔案,也不要直接把檔案拖曳至Excel中,而試著從Excel上方的「資料 > 取得資料 > 從檔案 > 從文字/CSV」;Office 2013以前的Excel則為「資料 > 取得外部資料 > 從文字檔」。
編碼卡關經驗
我通常匯出檔案都是用utf-8-sig,在後面會提到。本來覺得沒什麼問題,也沒想過我會寫一篇關於編碼的文章。但就在今天,我在Mac上匯出了一份地址清單,並且在雙系統的Windows中要使用郵局的3+3郵遞區號轉碼軟體,結果匯入的檔案一直顯示亂碼,在多次的測試後終於成功,也才有了這篇文章。

使用情境決定檔案格式
Excel檔和CSV檔的特性不同,Excel的檔案較大,讀取寫入較慢,而且欄數和列數都有上限,列數的上限為1048576,但比較容易使用,而且在我的經驗中,Excel檔比較不容易有亂碼的問題產生。
相反,CSV檔的檔案較小,讀取寫入較快,沒有欄數與列數的限制,壞處是有些人不習慣使用CSV檔,不太知道怎麼和它相處。
總結來說,如果你的資料量不大,而且產出的檔案需要給其他人使用,建議你匯出成xlsx就可以了。但如果你的檔案是自己要用的,像是分析的過程中匯出暫存檔,那csv當然是個比較好的選擇,而且在Python中讀取檔案的時候也可以指定編碼,彈性更高。
選擇適合的編碼
以下列了三種編碼,不知道哪一種適合你嗎?別懷疑,全部試一次就對了。
UTF-8
UTF-8是pandas預設的編碼格式,但通常用這個方式都會出現亂碼,我只是寫出來讓大家知道一下。
path = '路徑'
df.to_csv(path + '/file_name.csv', index=False, encoding='utf-8')
df.to_csv(path + '/file_name.xlsx', index=False, encoding='utf-8')
UTF-8-Sig
UTF-8-Sig和UTF-8的主要差別是前者是UTF-8 with BOM (Byte Order Mark),在Win10中翻譯成「具有BOM的UTF-8」,後者沒有BOM,總之有BOM的比較好。這個方式通常都可以順順利利、平平安安的匯出檔案,這也是網路上最多人推薦的用法。
順帶一提,utf-8-sig事實上有兩種寫法,utf-8-sig與utf_8_sig,兩者似乎有微秒的差異,兩個都可以試一下。
path = '路徑'
df.to_csv(path + '/file_name.csv', index=False, encoding='utf-8-sig')
df.to_csv(path + '/file_name.xlsx', index=False, encoding='utf-8-sig')
Big5
如果utf-8-sig不幸未能完成任務,那你可以試試big5。在我上面提到的郵遞區號3+3轉換的案例中,我最後也是用big5解決,但詭異的地方在於,用big5匯出的檔案在我的Mac上反而顯示為亂碥,在郵局的軟體中卻正常顯示。沒關係,我已經不想追究原因了。
path = '路徑'
df.to_csv(path + '/file_name.csv', index=False, encoding='big5')
df.to_csv(path + '/file_name.xlsx', index=False, encoding='big5')
其他編碼
如果不幸的,以上三種方法都不能達成你的目的,你可以到codecs — Codec registry and base classes中,嘗試其他可以顯示Traditional Chinese的編碼。我在這個頁面中也找到一個ANSI的編碼,這個編碼似乎可以達成我的目的,但只有在Windows上可以使用,偉大的Python看起來也沒辦法在Mac上把UTF-8轉成ANSI,總之我最後是放棄了,也勸你不要輕易嘗試這個方法。

編碼錯誤
匯出檔案的時候,Python可能會回傳以下編碼錯誤的訊息,像是:
'utf-8' codec can't encode character '\\u6052' in position 19: illegal multibyte sequence
這個錯誤的原因是某些字元沒辦法完成編碼,可以使errors參數忽略,如下:
df.to_csv(path + '/file_name.csv', index=False, encoding='utf-8-sig', errors='ignore')
errors這個參數可能需要更新pandas才可以使用,像我從1.0.1更新到1.2.4後,才能順利使用。