我想阅读holiday.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 :(得分: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"
}
答案 1 :(得分: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 $row
和lassign
这些值将值列表提取到我可以检查的变量中。
注意:struct::matrix
并不适合使用。人们说它很慢,而且更糟糕的是它在隐藏低级细节方面并不是很擅长。在某些情况下, less 使用普通的Tcl I / O读取csv文件,使用::csv::split
从每行获取字段并在使用{{ 1}}再次将它们转换为csv字符串。
文档:chan,csv,expr,for,foreach,if,lassign,{{3 }},llength,lmap,open,package,proc,return,set,string