读取csv文件并与今天的日期进行比较



我想读取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:30ET030,12 ((( US MARKET CLOSED -   US HOLIDAY ))) 17"
    } else {
        putserv "privmsg #channel :030,4 09:30ET030,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:30ET030,12 ((( US MARKET CLOSED -   US HOLIDAY ))) 17"
} else {
    putserv "privmsg #channel :030,4 09:30ET030,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

相关内容

  • 没有找到相关文章

最新更新