難度:★★進階
致謝:本文站在文山社大Oliver同學肩膀上開展。沒有Oliver先前對csv檔案的整理報告,即無拙文。感謝Oliver。
csv檔案功能、格式等略,不清楚的讀者請自行求教Google老師。以下單刀直入立馬介紹csv讀寫。
程式重點在第9列:
運用Python standard library中的csv模組讀取csv檔案,可輕易將檔案內容轉為Python內建的list或tuple型態。轉成了這些型態(尤其是list),後續的查詢、修改、新增、刪除等常見資料存取作業,就變得非常簡單。
試想一下:假如沒有csv模組(或其他類似third party)可用,要怎樣讀取csv檔呢?很可能拿文字檔I/O充數。程式大概如下:
plainText就是檔案內容。不過那是真"plain text",普通字串耳。轉換list/tuple,行,可惜轉出來的list/tuple完全走調。請看下面的程式碼和輸出:
原來的csv檔:
用一般文字檔方式讀檔,轉出的list亂七八糟,不成人樣。一看即知那不是正確的結果。
用csv模組讀檔,轉出的list才是我們想要的樣子。
拿csv當一般文字檔來讀,又想轉出正確的list,大概得自行寫csv parser。不算太難,卻煩。功力不足寫出的parser肯定一堆。
講到這裡,大家清楚csv模組的功效了吧?像parsing這種dirty work,模組會替我們代勞,乖巧勤快又品質保證。這麼好用的工具豈能擱著讓它?
讀取csv檔有兩點補充:
encoding='utf-8-sig'
參數:
但csv如為Big5編碼的中文檔案,則勿加encoding
參數,或者encoding
用'Big5'
, 'cp950'
,甚至None
:
紅字表重要 |
||||
---|---|---|---|---|
1 | 整數 | 123 |
'123' |
不管文字數字,都 轉換成str。 |
2 | 浮點數 | -.805 |
'-.805' |
同上。 |
3 | Boolean | True |
'True' |
仍然是字串,不會 自動轉為 True 。 |
4 | 全欄無引號 | 鳳閣恩仇未了情 |
'鳳閣恩仇未了情' |
就是字串。 |
5 | 前後綴雙引號"" |
"紫釵記" |
'紫釵記' |
雙引號去除,效果 等於全欄無引號。 |
6 | 前後綴單引號'' |
'胡不歸' |
"'胡不歸'" |
前後單引號均保留。 |
7 | 前後均無引號,中插單引號 | A Bug's Life |
"A Bug's Life" |
單引號不須以\ 跳脫。 |
8 | 前後綴雙引號,中插單引號 | "A Bug's Life" |
"A Bug's Life" |
同上。 |
9 | 前後綴雙引號,中置逗點, |
"男燒衣,女燒衣", 1975, 白駒榮,杜煥 |
['男燒衣,女燒衣', ' 1975', ' 白駒榮', '杜煥'] |
"男燒衣,女燒衣" 視為一欄。list只有4個元素。 注意:原字串中的 1975 、白駒榮 分別和其前面的 , 間有一空白,轉出來的 list元素隨之前置 空白。而原 杜煥 前面並無空格,list 亦未留白。 |
10 | 前後綴單引號,中置逗點 | '男燒衣,女燒衣', 1975, 白駒榮,杜煥 |
["'男燒衣", " 女燒衣'", ' 1975', ' 白駒榮', '杜煥'] |
'男燒衣,女燒衣' 視為兩欄。list共有5個元素。 |
11 | 欄首一段包雙引號 | "萬惡"淫為首 |
'萬惡淫為首' |
雙引號刪除。 |
12 | 欄中一段包雙引號 | 萬惡"淫"為首 |
'萬惡"淫"為首' |
雙引號保留。 |
13 | 欄末一段包雙引號 | 萬惡淫為"首" |
'萬惡淫為"首"' |
雙引號保留。 |
14 | 首末各一段包雙 引號 |
"萬惡"淫為"首" |
'萬惡淫為"首"' |
欄首雙引號去除,欄末保留。 |
15 | 欄首一段包單引號 | '萬惡'淫為首 |
"'萬惡'淫為首" |
單引號保留。 |
16 | 欄中一段包單引號 | 萬惡'淫'為首 |
"萬惡'淫'為首"' |
單引號保留。 |
17 | 欄末一段包單引號 | 萬惡淫為'首' |
"萬惡淫為'首'" |
單引號保留。 |
18 | 首末各一段包單 引號 |
'萬惡'淫為'首' |
"'萬惡'淫為'首'" |
單引號全保留。 |
19 | 前單引號,後雙 引號 |
'雷鳴金鼓戰笳聲" |
'\'雷鳴金鼓戰笳聲"' |
單雙引號均保留。單引號以\ 跳脫(escape)。 |
20 | 欄中分插雙單引號 | 大鬧"廣昌'隆 |
'大鬧"廣昌\'隆' |
同上。 |
21 | 前綴雙引號,但 無相對應的後綴 雙引號 |
"重慶森林,1994,王家衛 ↩️ 悲情城市,1989, 侯孝賢 ↩️ 霸王別姬,1993, 陳凱歌 |
[['重慶森林,1994,王家衛\n悲情城市,1989, 侯孝賢\n霸王別姬,1993, 陳凱歌']] |
系統誤判。原資料3筆各3欄,list誤作1筆1欄。 |
22 | 中插單一雙引號 | 重慶"森林,1994,王家衛 ↩️ 悲情城市,1989, 侯孝賢 ↩️ 霸王別姬,1993, 陳凱歌 |
[['重慶"森林', '1994', '王家衛'], ['悲情城市', '1989', ' 侯孝賢'], ['霸王別姬', '1993', ' 陳凱歌']] |
list正確列出 3筆3欄,無誤判。 雙引號保留。 |
使用csv模組寫檔,同樣享受操作方便和資料正確的好處。以上程式輸出:
用Excel開啟。正確無誤:
假設以普通文字檔方式寫檔,程式碼大概會是:
寫入固然成功。但plainText.csv卻長這個模樣:
用Excel開啟:
資料滲沙挾石,雜草叢生。
一言蔽之,檔案寫入也請採用csv模組,別重新發明輪子。
另外,寫檔須注意一點:open()
方法要加上newline=''
參數。
以上程式碼未加這參數,後果是:產生的csv檔在換列處會多製造一個carriage return符號,即16進位的0D。本來Windows文字檔換列碼是16進位的0D 0A,多一個c/r,變成0D 0D 0A。以Windows的notepad「記事本」瀏覽,看似正常。用notepad++開啟,則看到兩列間插入一空列:
Excel開檔亦如此:
所以,欲掃除文盲,不,是掃除空列,寫檔毋忘newline=''
,除非真想製造空列效果。
建議無論是讀是寫,都恭請standard library的csv模組大爺出馬,勿土法練鋼拿一般文字檔I/O勉強湊合。文字檔I/O對象是普通文件。對csv這樣有格式要求的檔案,引進專屬模組才事半功倍。
外部參考資料:
如何使用Excel開啟UTF-8格式的CSV檔案
csv
文字檔
讀檔
寫檔
standard library
csv模組
newline