我想读取holiday.csv
文件并将该文件中的日期与今天的日期进行比较,以确定今天是否是假期。
这是我到目前为止所拥有的...
文件=假日.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 : 030,4 09:30ET 030,12 ((( US MARKET CLOSED - US HOLIDAY ))) 17"
} else {
putserv "privmsg #channel : 030,4 09:30ET 030,12 ((( US MARKET OPEN ))) 17"
}
}
我会先从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 : 030,4 09:30ET 030,12 ((( US MARKET CLOSED - US HOLIDAY ))) 17"
} else {
putserv "privmsg #channel : 030,4 09:30ET 030,12 ((( US MARKET OPEN ))) 17"
}
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 替代 Tcl 8.4 和 8.5