tcl - Reading from a CSV file -


i have csv file containing many rows , columns 2 of similar to:

  horizontal-1 acc. filename      horizontal-2 acc. filename  rsn88_sfern_fsd172.at2          rsn88_sfern_fsd262.at2   rsn164_impvall.h_h-cpe147.at2   rsn164_impvall.h_h-cpe237.at2   rsn755_lomap_cyc195.at2         rsn755_lomap_cyc285.at2   rsn1083_northr_gle170.at2       rsn1083_northr_gle260.at2   rsn1614_duzce_1061-n.at2        rsn1614_duzce_1061-e.at2   rsn1633_manjil_abbar--l.at2     rsn1633_manjil_abbar--t.at2   rsn3750_capemend_lfs270.at2     rsn3750_capemend_lfs360.at2   rsn3757_landers_npf090.at2      rsn3757_landers_npf180.at2  rsn3759_landers_wwt180.at2      rsn3759_landers_wwt270.at2   rsn4013_sansimeo_36258021.at2   rsn4013_sansimeo_36258111.at2   rsn4841_chuetsu_65004ns.at2     rsn4841_chuetsu_65004ew.at2   rsn4843_chuetsu_65006ns.at2     rsn4843_chuetsu_65006ew.at2   rsn4844_chuetsu_65007ns.at2     rsn4844_chuetsu_65007ew.at2   rsn4848_chuetsu_65011ns.at2     rsn4848_chuetsu_65011ew.at2  

in csv file wanna headers "horizontal-1 acc. filename , horizontal-2 acc. filename" , line line names of each row under these headers 1 @ time ?

any suggestion ?

thanks rg.

package require csv package require struct::matrix  ::struct::matrix m m add columns 2  set chan [open data.csv] ::csv::read2matrix $chan m close $chan  lassign [m row 0] header1 header2  {set r 1} {$r < [m rows]} {incr r} {     puts -nonewline [format {%s = %-30s  } $header1 [m cell 0 $r]]     puts [format {%s = %s} $header2 [m cell 1 $r]] }  m destroy 

i find easiest way deal csv data sets using matrix. matrix sort of two-dimensional vector built-ins searching, sorting , rearranging columns , rows.

first, create matrix , call m. have 2 columns beginning, no rows yet.

::struct::matrix m m add columns 2 

open channel read data file. pass channel , matrix name ::csv::read2matrix command. command read csv data , create matrix row each data row. data fields stored in columns.

set chan [open data.csv] ::csv::read2matrix $chan m close $chan 

to header strings, retrieve row 0.

lassign [m row 0] header1 header2 

to iterate on data rows, go 1 (if didn't have headers, 0) under m rows, number of rows in matrix.

there handy report facility works matrices, i'll use for loop here. i'm guessing how want data presented:

for {set r 1} {$r < [m rows]} {incr r} {     puts -nonewline [format {%s = %-30s  } $header1 [m cell 0 $r]]     puts [format {%s = %s} $header2 [m cell 1 $r]] } 

if you're done matrix, might destroy it.

m destroy 

solution specific problem in comments.

package require csv package require struct::matrix  ::struct::matrix m  set chan [open foo.csv] ::csv::read2matrix $chan m , auto close $chan  set f1 [m search column 0 "result id"] set headerrow [lindex $f1 0 1] set f2 [m search rect 0 $headerrow 0 [expr {[m rows] - 1}] ""] set f3 [m search row $headerrow "horizontal-1 acc. filename"] set f4 [m search row $headerrow "horizontal-2 acc. filename"]  set top [expr {$headerrow + 1}] set bottom [expr {[lindex $f2 0 1] - 1}] set left [lindex $f3 0 0] set right [lindex $f4 0 0]  puts [format {vector=[ %s ]} [concat {*}[m rect $left $top $right $bottom]]] m destroy 

obviously, need change filename correct name. there no error handling: in such simple script it's better have script fail , correct whatever went wrong.


solution second problem, comments below:

package require csv package require struct::matrix  ::struct::matrix m  set chan [open _searchresults.csv] ::csv::read2matrix $chan m , auto close $chan  set f1 [m search column 0 {result id}] set headerrow [lindex $f1 0 1]  set f2 [m search -glob rect 0 $headerrow 0 [expr {[m rows] - 1}] { these*}] set numofrow [lindex $f2 0 1]  set headercol1 [m search row $headerrow { horizontal-1 acc. filename}] set headercol2 [m search row $headerrow { horizontal-2 acc. filename}]    set indexheaderh1col [lindex $headercol1  0 0] set indexheaderh2col [lindex $headercol2  0 0]  set rows [m rect $indexheaderh1col [expr {$headerrow+1}] $indexheaderh2col [expr {$numofrow-1}]]  set rows [lmap row $rows {     lassign $row b     list [string trim $a] [string trim $b] }]  foreach row $rows {     puts [format {%-30s   %s} {*}$row] }  puts [format {vector=[ %s ]} [concat {*}$rows]] 

comments:

  • you don't need set number of columns if use read2matrix auto
  • in file, there no empty cell after table. instead, need search string beginning " these"
  • since each cell holds space character followed value, need trim off space around value, otherwise concatenation go wrong. part lmap command fixes that
  • always brace expressions

documentation: + (operator), - (operator), < (operator), chan, close, concat, csv (package), expr, for, format, incr, lassign, lindex, lmap (for tcl 8.5), lmap, open, package, puts, set, struct::matrix (package), {*} (syntax)


Comments