Dear all,
Please consider the stupid function below: I intend to run through every
line of an input stream to process the current line up to the last one.
The do* formulation appeared first, but it becomes awkward since I have
to supply the same (long) expression for variable initialisation and
update.
Can someone suggest me something better?
Thanks in advance.
(defun file-to-lists (input-file-name)
"reads a test file: return a list of lines, ie a sublist of string
tokens"
(with-open-file (stream (make-pathname :name input-file-name)
:direction :input)
(let ((acc (list)))
(do* ((current-line (read-line stream nil 'eof)
(read-line stream nil 'eof))) ;current line of the stream
((equal current-line 'eof) (nreverse acc))
(push (str-tokenize current-line) acc)))))
--
-----------------------------------
Jonathan BAILLEUL, Doctorant
GREYC Image - Université de Caen
http://www.greyc.ismra.fr/~bailleul
On Thu, 04 Sep 2003 11:37:08 +0200, "Jonathan.Bailleul" <········@greyc.ismra.fr> wrote:
> Please consider the stupid function below: I intend to run through
> every line of an input stream to process the current line up to the
> last one. The do* formulation appeared first, but it becomes
> awkward since I have to supply the same (long) expression for
> variable initialisation and update.
>
> Can someone suggest me something better?
> Thanks in advance.
>
> (defun file-to-lists (input-file-name)
> "reads a test file: return a list of lines, ie a sublist of string
> tokens"
> (with-open-file (stream (make-pathname :name input-file-name)
> :direction :input)
> (let ((acc (list)))
> (do* ((current-line (read-line stream nil 'eof)
> (read-line stream nil 'eof))) ;current line of the stream
> ((equal current-line 'eof) (nreverse acc))
> (push (str-tokenize current-line) acc)))))
Something like this (untested)?
(defun file-to-lists (input-file-name)
(with-open-file (stream (make-pathname :name input-file-name)
:direction :input)
(loop for line = (read-line stream nil)
while line
collect (str-tokenize line))))
Edi.
Jonathan.Bailleul wrote:
> Dear all,
>
> Please consider the stupid function below: I intend to run through every
> line of an input stream to process the current line up to the last one.
> The do* formulation appeared first, but it becomes awkward since I have
> to supply the same (long) expression for variable initialisation and
> update.
>
> Can someone suggest me something better?
> Thanks in advance.
>
>
> (defun file-to-lists (input-file-name)
> "reads a test file: return a list of lines, ie a sublist of string
> tokens"
> (with-open-file (stream (make-pathname :name input-file-name)
> :direction :input)
> (let ((acc (list)))
> (do* ((current-line (read-line stream nil 'eof)
> (read-line stream nil 'eof))) ;current line of the stream
> ((equal current-line 'eof) (nreverse acc))
> (push (str-tokenize current-line) acc)))))
>
Standard reply (untested)
(defun file-to-list (ifn)
(with-open-file (stream ifn :direction :input)
(loop for line of-type (or null string) = (read-line stream nil nil)
while line
collect (str-tokenize line))))
Cheers
--
Marco
Marco Antoniotti <·······@cs.nyu.edu> writes:
> (loop for line of-type (or null string) = (read-line stream nil nil)
> while line
> collect (str-tokenize line))
Did you intentionally indent COLLECT two spaces from WHILE?
I understand doing so with WHEN but this one seems unusual.
Kalle Olavi Niemitalo wrote:
> Marco Antoniotti <·······@cs.nyu.edu> writes:
>
>
>> (loop for line of-type (or null string) = (read-line stream nil nil)
>> while line
>> collect (str-tokenize line))
>
>
> Did you intentionally indent COLLECT two spaces from WHILE?
> I understand doing so with WHEN but this one seems unusual.
Yes, I did it intentionally. I always wished cl-indent-function in
Emacs did the same.
It's one of my quirks.
Cheers
--
marco
Jonathan.Bailleul wrote:
The questionable part of your code may be this fragment:
> (with-open-file (stream (make-pathname :name input-file-name)
Calling make-pathname is a highly unportable way of denoting a file to
open. It might work reliably for a filename like "mydata" but would
not necessarily work for a filename like "myname.txt" and would be
unlikely to work for a filename like "foo/myname.txt".
The conversion between physical pathnames and filename strings is
necessarily platform dependent, but the default implementation behavior
could be extended to handle each of the examples in the above paragraph
correctly, while your attempt to help out the system only confuses
things.
Probably you should write
(with-open-file (stream input-file-name) ...)
which is exactly the same as writing
(with-open-file (stream (pathname input-file-name)) ...)
Generally you should use make-pathname only when you are doing explicit
calculus on pathnames.
Jonathan.Bailleul <········@greyc.ismra.fr> wrote:
+---------------
| The do* formulation appeared first, but it becomes awkward since I have
| to supply the same (long) expression for variable initialisation and
| update.
...
| (with-open-file (stream (make-pathname :name input-file-name)
| :direction :input)
| (let ((acc (list)))
| (do* ((current-line (read-line stream nil 'eof)
| (read-line stream nil 'eof)))
| ((equal current-line 'eof) (nreverse acc))
| (push (str-tokenize current-line) acc)))))
+---------------
Others have shown you the standard idioms using LOOP, so I won't,
but will make a few small observations:
- You don't need DO* here; DO is enough.
- You don't need a separate LET; DO is enough.
- You don't need to call LIST to get an empty list; a constant will do.
- Since your EOF object is a symbol, your don't need EQUAL; EQ is enough.
- An idiom useful especially with DO[1] is to use #= & ## syntax when
repeating an long form.
Putting it all together, we get:
(with-open-file (stream input-file-name)
(do ((acc '())
(line #1=(read-line stream nil 'eof) #1#))
((eq line 'eof) (nreverse acc))
(push (str-tokenize line) acc)))
-Rob
[1] Note: This is not needed with LOOP's "for var = form", since it's
already implied. That is, "for var = form" has the same meaning as
"for var = #1=form then #1#".]
-----
Rob Warnock, PP-ASEL-IA <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607