Csv是一個棘手的格式,通常不適合使用不完整的解析器讀取csv數據。當然,這從來沒有阻止任何人這樣做。
然而,如果有人想要這本書,咒語就是這樣。
package require csv
package require struct::matrix
創建矩陣的數據結構將從CSV文件保存數據,使我們與它的工作:
::struct::matrix m
m
現在是在當前名字空間的命令(你可以添加命名空間到該名稱以在另一個名稱空間中創建它)。一旦你完成矩陣,你應該打電話m destroy
。
您也可以讓模塊名的矩陣命令,並使用它通過一個變量:
set m [::struct::matrix]
現在,你有一個矩陣,您可以CSV文件的內容加載到:
set ch [open holiday.csv]
::csv::read2matrix $ch m , auto
chan close $ch
(你可以用m serialize
檢查它(我已經添加了可讀性一些換行):)
3 3 {
{{Dec 25} Christmas {US Holiday }}
{{Jan 1} {New Year} {US Holiday }}
{{Jan 19} {Martin Luther King} {US Holiday}}
}
要搜索一個特定日期:
proc findDate date {
m search column 0 $date
}
要搜索的第三列給定的字符串:
proc findStr str {
m search -glob column 2 $str*
}
(由於某些列的值都垃圾尾隨空白,我們需要按string match
規則搜索(-glob
)而不是默認的完全匹配。)
這兩個命令都返回搜索出現的單元格列表。這些單元由列/行對的值來表示,例如, {0 2}
爲第一列第三行的匹配。
如果我們只是想找出是否在文件中出現一個給定的日期,該斷言可以這樣做:
proc hasDate date {
expr {[llength [findDate $date]] > 0}
}
但是,如果我們想確保該行的日期是在真正含有美國假期,我們還需要檢查第三欄。有很多方法可以做到這一點。對於他們中的一個,我首先需要一個輔助函數變換單元描述符的列表行數的列表:
proc getRowNums cells {
lmap cell $cells {lindex $cell 1}
}
現在我可以檢查日期和字符串,像這樣:
proc hasDateAndString {date str} {
set r1 [getRowNums [findDate $date]]
set r2 [getRowNums [findStr $str]]
# do any rows overlap?
foreach r $r1 {
if {$r in $r2} {
return true
}
}
return false
}
這通過檢查兩行列表是否共享任何值來工作。如果他們不這樣做,日期不會指定美國的假期。
另一種方式是按行遍歷矩陣,並檢查各行的相關項目:
proc hasDateAndString {date str} {
for {set row 0} {$row < [m rows]} {incr row} {
lassign [m get row $row] dateVal - strVal
if {$date eq $dateVal && [string match $str* $strVal]} {
return true
}
}
return false
}
的每一行我看,我提取使用m get row $row
和lassign
這些值轉換成變量值的列表我可以檢查。
注意:struct::matrix
是不是很好的合作。人們說這很慢,而且更糟糕的是它並不能很好地隱藏低級細節。在某些情況下,它是減去使用普通Tcl I/O讀取csv文件,使用::csv::split
從每行獲取字段,並在使用::csv::join
將它們再次轉換爲csv字符串後將它們寫回。
文檔:chan,csv,expr,for,foreach,if,lassign,llength,lmap,open,package,proc,return,set,string,struct::matrix
lmap replacement for Tcl 8.4 and 8.5
你可以張貼一些來自「holiday.csv」文件的行?不是全部,但是說3-4。 – Paul 2014-12-05 16:05:05
[This](http://wiki.tcl.tk/3189)可能對您有用。 – Jerry 2014-12-05 16:12:45
這看起來像是Tcl和僞代碼的混合體。 – 2014-12-05 22:20:27