Subject: Re: parsing a CSV line
From: (Rob Warnock)
Date: Mon, 20 Sep 2004 21:38:08 -0500
Newsgroups: comp.lang.lisp
Message-ID: <>
Jock Cooper  <> wrote:
| Parsing a CSV line is nearly trivial, but can be a pain to handle the 
| quote text qualifier and backslashes.  Here is some code I wrote but
| was wondering if there might be a more elegant or shorter way:
| (defun get-csv-line (line)
|   ...[61 lines omitted...)

Here's mine, which I've been using for some time. It's about half
the length of yours (not that LOC is a good measure of anything),
uses a slightly simpler parser (though I admit I went through
*several* revisions before this version), and uses LOOP...ACROSS
to avoid having to break the string into a list of characters
up-front (though it probably still conses an equivalent amount):

;;; PARSE-CSV-LINE -- 2004-03-06/
;;; Parse one CSV line into a list of fields, ignoring comment
;;; lines, stripping quotes and field-internal escape characters.
;;; Lexical states: '(normal quoted escaped quoted+escaped)
(defun parse-csv-line (line)
  (when (or (string= line "")		; special-case blank lines
	    (char= #\# (char line 0)))	; or those starting with "#"
    (return-from parse-csv-line '()))
  (loop for c across line
	with state = 'normal
	and results = '()
	and chars = '() do
    (ecase state
       (case c
         ((#\") (setq state 'quoted))
         ((#\\) (setq state 'escaped))
          (push (coerce (nreverse chars) 'string) results)
	  (setq chars '()))
         (t (push c chars))))
       (case c
         ((#\") (setq state 'normal))
         ((#\\) (setq state 'quoted+escaped))
         (t (push c chars))))
      ((escaped) (push c chars) (setq state 'normal))
      ((quoted+escaped) (push c chars) (setq state 'quoted)))
       (push (coerce (nreverse chars) 'string) results)	; close open field
       (return (nreverse results)))))


Rob Warnock			<>
627 26th Avenue			<URL:>
San Mateo, CA 94403		(650)572-2607