Python寫的csv文件,如何讓 Excel 雙擊打開不亂碼?

  • 2019 年 10 月 4 日
  • 筆記

我們常常需要在 Python 中輸出 CSV 文件,但你可能會發現,這些輸出的 CSV文件,不能雙擊使用 Excel 打開,否則中文會變成亂碼。例如下面這段程式碼:

import pandas as pd  datas = [    {        'name': '王小一',        'age': 29,        'address': '北京'    },    {        'name': '張小二',        'age': 18,        'address': '四川'    },    {        'name': '李小三',        'age': 60,        'address': '上海'    }]  df = pd.DataFrame(datas)df.to_csv('person.csv', index=False)

如果雙擊使用 Excel 打開,你會發現中文變成了亂碼,如下圖所示:

這是因為,當你執行程式碼 df.to_csv('person.csv',index=False)時,它默認會以 UTF-8編碼方式寫 CSV 文件。但是當你雙擊 CSV 使用 Excel打開時,Excel 會以 GBK 編碼來讀這個文件,這就導致了亂碼的發生。

所以,如果是簡單的中文,你可以把編碼方式人工指定為 GBK:

import pandas as pd  datas = [    {        'name': '王小一',        'age': 29,        'address': '北京'    },    {        'name': '張小二',        'age': 18,        'address': '四川'    },    {        'name': '李小三',        'age': 60,        'address': '上海'    }]  df = pd.DataFrame(datas)df.to_csv('person.csv', index=False, encoding='gbk')

此時再雙擊使用 Excel 打開,中文就能正常顯示了,如下圖所示:

但 GBK 編碼的字符集不夠完善,所以如果文本中包含超出 GBK 字符集的內容,就會導致編碼錯誤,如下圖所示:

這個時候怎麼辦呢?

實際上當你雙擊打開 CSV 的時候,Excel會檢查文件的第一個字元,如果這個字元是 BOM,那麼他就知道應該使用 UTF-8編碼方式來打開這個文件。所謂的 BOM指的是 byte-order mark

BOM對應的 Unicode 碼為 ufeff,所以當我們使用 UTF-8編碼方式生成 CSV 以後,再增加一步,把 BOM 寫入到文件的第一個字元:

with open('person.csv', encoding='utf-8') as f:    content = f.read()content_with_bom = 'ufeff' + content  with open('person.csv', 'w', encoding='utf-8') as f:    f.write(content_with_bom)

完整程式碼如下圖所示:

此時,新的 CSV 文件可以直接雙擊通過 Excel 打開,並且中文支援完全正常,如下圖所示:

這樣生成的 Excel 雖然在 Excel 上顯示沒有問題,但是如果你發給別人,別人使用 Python 自帶的 csv 模組打開,就會發現 address這一列的列名不是 address而是 ufeffaddress,如下圖所示:

這個 BOM字元雖然肉眼看不到,但是程式能夠看到,這就會導致別人在讀這個 CSV 文件的時候非常不方便。如果直接使用 address去讀,還會報錯:

難道此時,需要先用普通方式讀取 csv 文件,移除第一個 BOM 字元,然後再傳給 CSV 模組嗎?這未免太過麻煩。

好在 Python 只帶了處理 BOM的編碼方式 utf-8-sig,無論是寫文件還是讀文件,只要使用這個編碼方式,Python 在寫文件的時候會自動加上 BOM,在讀文件的時候會自動刪除 BOM。

所以生成 CSV 文件的程式碼如下:

import pandas as pd  datas = [    {        'name': '王小一',        'age': 29,        'address': '北京'    },    {        'name': '張小二',        'age': 18,        'address': '四❤川'    },    {        'name': '李小三',        'age': 60,        'address': '上海'    }]  df = pd.DataFrame(datas)df.to_csv('person.csv', index=False, encoding='utf-8-sig')

此時生成的 CSV 文件,可以直接雙擊使用 Excel 打開,中文正常顯示。

如果要使用 Python 的 CSV 模組讀取文件,也非常簡單,如下圖所示:

讀取出來的內容直接使用,BOM 已經被 Python 自動移除了。