efritz
efritz

Reputation: 5203

Reading Delimited Input in Lisp

In Common Lisp, I need to capture user input in the form of a list of reals. This list is terminated by two zeros in a row. For example, 5.0 0 6.0 3 2.0 5 1.0 7 13.0 8 0 0 should return the list (5.0 0 6.0 3 2.0 5 1.0 7 13.0 8).

I've come across the function read-delimited-list, which takes a single character as an ending point. I can stop at a single zero, but I'm not sure how to expand this function, and I don't know of another function that takes a delimited string instead of a char.

EDIT Thanks to the accepted answer, I've developed the following:

(butlast (loop for y = -1 then x for x = (read stream) until (and (= 0 x) (= 0 y))
    collect x)))

It seems a bit more readable to me (and at this point I'm openly admiting that my Lisp eyes are only 3 days old), and I'm not sure about performance implications (does collect append or reverse the list after the loop exits scope? is there an easier way to chop off the last element, or simply not append it?).

Upvotes: 2

Views: 927

Answers (2)

Svante
Svante

Reputation: 51551

The best way to parse numbers in Common Lisp is to use the library parse-number. If your user input can be read line by line, you can simply split the lines on whitespace and use parse-number on the results.

Upvotes: 0

Vsevolod Dyomkin
Vsevolod Dyomkin

Reputation: 9451

For such simple case you can just use read in a loop, collect the results read so far and stop, when the last two are zeros.

(defun read-double-zero-terminated-list (stream)
  (do* ((prev -1 val)
        (val (read stream) (read stream))
        list)
       ((and (zerop prev) (zerop val)) (reverse (cdr list)))
     (push val list)))

read-delimited-list is intended for the cases of creating specialized syntax, so it's probably overkill here.

Upvotes: 4

Related Questions