1

我想阅读该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 :\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"
    }

}
4

2 回答 2

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"
}
于 2014-12-06T10:07:15.357 回答
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不是很好用。人们说它很慢,更糟糕的是它不太擅长隐藏底层细节。在某些情况下,使用普通 Tcl I/O 读取 csv 文件的工作量较少::csv::split,用于从每一行获取字段并在使用后将它们写回::csv::join以再次将它们转换为 csv 字符串。

文档:chancsvexprforforeachiflassignllengthlmapopenpackageprocreturnsetstringstruct::matrix

Tcl 8.4 和 8.5 的 lmap 替换

于 2014-12-08T17:48:06.420 回答