2014-12-05 99 views
1

我想要閱讀holiday.csv文件,並將該文件中的日期與今天的日期進行比較,以確定今天是否爲假期。閱讀csv文件並與今天的日期比較

這裏是我迄今...

文件= holiday.csv

日,假日名稱,美國假日即:

Dec 25,Christmas,US Holiday 
Jan 1,New Year,US Holiday 
Jan 19,Martin Luther King,US Holiday 

僞代碼:

package require csv 
proc mktopen {min hour day month weekday} { 
global stockchan 
    if {get date's from holiday.csv and compare to today's date if TRUE then} { 
     putserv "privmsg #channel :\0030,4 09:30ET\0030,12 (((US MARKET CLOSED - US HOLIDAY))) \017" 
    } else { 
     putserv "privmsg #channel :\0030,4 09:30ET\0030,12 (((US MARKET OPEN))) \017" 
    } 

} 
+0

你可以張貼一些來自「holiday.csv」文件的行?不是全部,但是說3-4。 – Paul 2014-12-05 16:05:05

+0

[This](http://wiki.tcl.tk/3189)可能對您有用。 – Jerry 2014-12-05 16:12:45

+0

這看起來像是Tcl和僞代碼的混合體。 – 2014-12-05 22:20:27

回答

1

我會先從csv文件中獲取所有日期,然後將其與現在的日期進行比較。

不過,我不使用CSV包了,我沒當場命令從csv表只需要一欄,所以我將提供一個解決方案,而無需使用CSV包:

# Open the file for reading 
set holiday_file [open "holiday.csv" r] 

# Get all the holidays in a list called $holidays 
set holidays [list] 
while {[gets $holiday_file line] != -1} { 
    lappend holidays [lindex [split $line ,] 0] 
} 

# Get today's date in the required format 
set today [clock format [clock scan now] -format "%b %d"] 
lset today 1 [format %d [lindex $today 1]] 

# Compare with today's date 
if {[lsearch -exact $holidays $today] > -1} { 
    putserv "privmsg #channel :\0030,4 09:30ET\0030,12 (((US MARKET CLOSED - US HOLIDAY))) \017" 
} else { 
    putserv "privmsg #channel :\0030,4 09:30ET\0030,12 (((US MARKET OPEN))) \017" 
} 
+0

很好用...非常感謝你 – user2757400 2014-12-06 14:53:58

+0

@ user2757400真棒,隨時將答案標記爲已接受,同時解決問題:) – Jerry 2014-12-06 14:55:11

+0

我會在tcllib中使用'csv'包,很好用'struct :: matrix'包。這將有利於正確處理更惡劣的邊界情況,例如單元格內容中的字段或記錄分隔符。或者,如果失敗了,至少少寫代碼和測試代碼。 ;-) – 2014-12-06 19:54:20

0

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 $rowlassign這些值轉換成變量值的列表我可以檢查。

注意:struct::matrix是不是很好的合作。人們說這很慢,而且更糟糕的是它並不能很好地隱藏低級細節。在某些情況下,它是減去使用普通Tcl I/O讀取csv文件,使用::csv::split從每行獲取字段,並在使用::csv::join將它們再次轉換爲csv字符串後將它們寫回。

文檔:chancsvexprforforeachiflassignllengthlmapopenpackageprocreturnsetstringstruct::matrix

lmap replacement for Tcl 8.4 and 8.5