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 работать, чтобы читать файл csv с использованием обычного ввода/вывода Tcl, использовать ::csv::split
, чтобы получить поля из каждой строки и записать их после использования ::csv::join
, чтобы снова преобразовать их в строки csv.
Документация: chan, csv, expr, for, foreach, if, lassign, llength, lmap, open, package, proc, return, set, string, struct::matrix
lmap replacement for Tcl 8.4 and 8.5
Можете ли вы опубликовать некоторые строки из файла «holiday.csv»? Не все из них, но говорят 3-4. – Paul
[This] (http://wiki.tcl.tk/3189) может быть вам полезен. – Jerry
это похоже на смесь Tcl и псевдокода для меня. –