1 # Csv tcl package version 2.0
2 # A tcl library to deal with CSV (comma separated value)
3 # files, generated and readable by some DOS/Windows programs
4 # Contain two functions:
5 # csv2list string ?separator?
7 # list2csv list ?separator?
8 # which converts line from CSV file to list and vice versa.
10 # Both functions have optional "separator argument" becouse some silly
12 # program might use semicomon as delimiter in COMMA separated values
15 # Copyright (c) SoftWeyr, 1997-99
16 # Many thanks to Robert Seeger <rseeger1@nycap.rr.com>
17 # for beta-testing and fixing my misprints
18 # This file is distributed under GNU Library Public License. Visit
19 # http://www.gnu.org/copyleft/gpl.html
23 # Convert line, read from CSV file into proper TCL list
24 # Commas inside quoted strings are not considered list delimiters,
25 # Double quotes inside quoted strings are converted to single quotes
26 # Double quotes are stripped out and replaced with correct Tcl quoting
29 proc csv2list {str {separator ","}} {
31 set regexp [subst -nocommands \
32 {^[ \t\r\n]*("(([^"]|"")*)"|[^"$separator \t\r]*)}]
33 set regexp1 [subst -nocommands {$regexp[ \t\r\n]*$separator\(.*)$}]
34 set regexp2 [subst -nocommands {$regexp[ \t\r\n]*\$}]
36 while {[regexp $regexp1 $str junk1 unquoted quoted\
38 if {[string length $quoted]||$unquoted=="\"\""} {
39 regsub -all {""} $quoted \" unquoted
41 lappend list $unquoted
43 if {[regexp $regexp2 $str junk unquoted quoted]} {
44 if {[string length $quoted]||$unquoted=="\"\""} {
45 regsub -all {""} $quoted \" unquoted
47 lappend list $unquoted
48 if {[uplevel info exist csvtail]} {
49 uplevel set csvtail {""}
52 if {[uplevel info exist csvtail]} {
53 uplevel [list set csvtail $str]
55 return -code error -errorcode {CSV 1 "CSV parse error"}\
56 "CSV parse error: unparsed tail \"$str\""
62 proc list2csv {list {separator ","}} {
65 if {[string match {} $elem]||
66 [regexp {^[+-]?([0-9]+|([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?)$}\
70 regsub -all {"} $elem {""} selem
71 lappend l "\"$selem\""
74 return [join $l $separator]
77 proc csvfile {f {separator ","}} {
81 while {[gets $f line]>=0} {
82 if {[string length $csvtail]} {
83 set line "$csvtail\n$line"
84 } elseif {![string length $line]} {
88 set rec [csv2list $line $separator]
89 set buffer [concat $buffer $rec]
90 if {![ string length $csvtail]} {
95 if {[string length $csvtail]} {
96 return -code error -errorcode {CSV 2 "Multiline parse error"}\
97 "CSV file parse error"
102 proc csvstring {str {separator ","}} {
106 foreach line [split $str "\n"] {
107 if {[string length $csvtail]} {
108 set line "$csvtail\n$line"
109 } elseif {![string length $line]} {
113 set rec [csv2list $line $separator]
114 set buffer [concat $buffer $rec]
115 if {![ string length $csvtail]} {
120 if {[string length $cvstail]} {
121 return -code error -errorcode {CSV 2 "Multiline parse error"}\
122 "CSV string parse error"
127 package provide Csv 2.1