#| \#\"s in this file would need to be fiddled with. I'll post the common lisp file too. I wanted to try writing streaming csv processing. I was inspired by pizzapal doing classic AI in guile from PAIP. I'm doing something trivial in common lisp instead. Sisters of Mercy is good music, tangentially. pizzapal is working with xlsx I think, but there are shell utilities to convert those to csv. Streaming to me means that after an initial delay, data flows out at the same rate it flows in. Hypothetically only READs take time to do. This is all I want to do: 1. Read list of headers 2. Add or change the headers with 3 in mind 2b. Make an alist of conses often kinda like (\"header\" . (let ((last-val nil)) (lambda (&optional in out) (if (and in out) (format out \"~s\" (setf last-val (read in))) (values last-val))))) 3. call the closures corresponding to the headers from 2 for each row Input stream string: (defvar *test-input* \"\"this\" \"that\" \"the\" \"other\" 1 2 3 4 5 6 7 8 9 10 11 12 \") Output (stream): \"this:1\" \"that:2\" \"the:3\" \"other:4\" \"rowsum:10\" \"this:5\" \"that:6\" \"the:7\" \"other:8\" \"rowsum:36\" \"this:9\" \"that:10\" \"the:11\" \"other:12\" \"rowsum:78\" Arbitrary situational caveats: Has to stream cells, no #'read-line Can't use functions schemes won't have UTF8 streams dealt with not here. I have no internet on my usual machines while I very slowly rebuild some gentoo boxens so I have no way of posting this soon |# ;;;This will be what it sounds like (defvar *assoclosures*) (defun read-headings (in) \" (read-headings in) (Values (list )) Scheme probably doesn't have #'labels but w/e \" (let ((line (read-line in))) (labels ((get-heading (stream list) (let ((heading (read stream nil nil))) (if heading (get-heading stream (push heading list)) (nreverse list))))) (with-input-from-string (str line) (get-heading str (list)))))) (defun rw-each (headings in out) \" (rw-each headings in out) Like (mapl (lambda (x) (apply (cdar x) (list in out)))) Read (describe 'mapl) \" (when headings (apply (cdr (assoc (car headings) *assoclosures* :test 'string=)) (list in out)) (rw-each (cdr headings) in out))) (defun rw-rows (headings in out) \" (rw-rows headings in out) peeks for eof before doing #'rw-each \" (let ((peek1 (peek-char t in nil nil)) (peek2 (peek-char nil in nil nil))) (when peek2 (rw-each (copy-list headings) in out) (rw-rows headings in out)))) ;;;An alist like ;;;((\"string\" . (lambda (&optional in out) 'foo))) (setq *assoclosures* (list (cons \"this\" (let ((last-val nil)) (lambda (&optional in out) (if (and in out) (format out \"\"~a:~a\" \" \"this\" (setf last-val (read in))) last-val)))) (cons \"that\" (let ((last-val nil)) (lambda (&optional in out) (if (and in out) (format out \"\"~a:~a\" \" \"that\" (setf last-val (read in))) last-val)))) (cons \"the\" (let ((last-val nil)) (lambda (&optional in out) (if (and in out) (format out \"\"~a:~a\" \" \"the\" (setf last-val (read in))) last-val)))) (cons \"other\" (let ((last-val nil)) (lambda (&optional in out) (if (and in out) (format out \"\"~a:~a\" \" \"other\" (setf last-val (read in nil nil))) last-val)))) (cons \"rowsum\" (let ((last-val nil)) (lambda (&optional in out) (if (and in out) (format out \"\"~a:~a\"~%\" \"rowsum\" (setf last-val (reduce '+ (mapcan (lambda (x) (let ((n (funcall (cdr x)))) (and n (list n)))) *assoclosures*)))) last-val)))))) ;;;Test space delimited READable \"csv\" input. (defvar *test-input* \"\"this\" \"that\" \"the\" \"other\" 1 2 3 4 5 6 7 8 9 10 11 12 \") ;;;Test. (with-input-from-string (in *test-input*) (let ((headings (append (read-headings in) (list \"rowsum\")))) (terpri) (rw-rows headings in t))) (terpri) (quit)