Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is there a better way to read multiple values from a string

97 views
Skip to first unread message

Mirko Vukovic

unread,
Mar 27, 2015, 11:09:35 AM3/27/15
to
Hello,

I have a strings like "0 2 0 1". The number of values may vary, but
they all can be read using READ

Right now I do the following
(loop
:for (x pos) = (multiple-value-list
(read-from-string first-line nil nil :start (or pos 0)))
:while x
:collect x)


Is there a more idiomatic way to read all the tokens in the string and
return them as a list?

TIA,

Mirko

Pascal J. Bourguignon

unread,
Mar 27, 2015, 11:30:22 AM3/27/15
to
(with-input-from-string (in string)
(loop :for n = (read in nil nil)
:while n :collect n))

--
__Pascal Bourguignon__ http://www.informatimago.com/
“The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.” -- Carl Bass CEO Autodesk

Kaz Kylheku

unread,
Mar 27, 2015, 11:34:36 AM3/27/15
to
Just wait several years. When your article has long expired from Usenet servers
all over, a WJ reply will appear, with no References header or attribution,
solving this in whatever language he's tinkering with!

Here is one solution. Add a delimiting character to the string:

(with-input-from-string (s "1 2 3 4 x") (read-delimited-list #\x s))

Another solution: Add two delimiting characters. If we strategically
choose the characters #\( and #\), we get this:

(read-from-string "(1 2 3 4)")

Wrapping the first one up:

;; usual caveats about *read-eval* apply

(defun scan-numbers (str)
(let ((*read-eval* nil)) ;; omit if you trust the input
(with-input-from-string (s (catenate 'string str " x"))
(read-delimited-list #\x s))))

Ah fuck, that should be CONcatenate, of course! I can never remember
that piece of language abuse.

WJ

unread,
Mar 27, 2015, 3:52:41 PM3/27/15
to
Pascal J. Bourguignon wrote:

> Mirko Vukovic <mirko....@gmail.com> writes:
>
> > Hello,
> >
> > I have a strings like "0 2 0 1". The number of values may vary, but
> > they all can be read using READ
> >
> > Right now I do the following
> > (loop
> > :for (x pos) = (multiple-value-list
> > (read-from-string first-line nil nil :start (or pos 0)))
> > :while x
> > :collect x)
> >
> >
> > Is there a more idiomatic way to read all the tokens in the string and
> > return them as a list?
>
> (with-input-from-string (in string)
> (loop :for n = (read in nil nil)
> :while n :collect n))

This is a good example of how even elementary things are difficult
for worshippers of cumbersome CL (COBOL-Like).

Gauche Scheme:

(use srfi-42) ; list-ec

(call-with-input-string "0 2 0 1"
(lambda (port) (list-ec (: n port) n)))

===>
(0 2 0 1)

Another way:

(use srfi-13) ; string-tokenize
(map string->number (string-tokenize " 0 2 0 1 "))
===>
(0 2 0 1)

smh

unread,
Mar 28, 2015, 7:33:49 AM3/28/15
to

> (with-input-from-string (in string)
> (loop :for n = (read in nil nil)
> :while n :collect n))

The solution above will silently eliminate any token that happens to be NIL. While this might not matter in a particular application, the following is a standard idiom for handling stream eof:

(let ((eof (cons nil nil)))
(with-input-from-string (in string)
(loop as n = (read in nil eof)
until (eq n eof)
collect n)))

This relies on the fact that a fresh cons can eq to nothing else in the Lisp world except itself. A call to (gensym) or (make-symbol "") would serve as well, but a symbol is a slightly heavier object than a cons so creating and later gc is likely to have slightly more unnecessary overhead.

Speed obsessives might wrap a load-time-value around the cons form.

Teemu Likonen

unread,
Mar 28, 2015, 8:09:23 AM3/28/15
to
smh [2015-03-28 04:33:37-07] wrote:

> the following is a standard idiom for handling stream eof:
>
> (let ((eof (cons nil nil)))
> (with-input-from-string (in string)
> (loop as n = (read in nil eof)
> until (eq n eof)
> collect n)))

I think it's better to let READ signal an END-OF-FILE condition and then
handle it.

(with-input-from-string (in "t nil 1 2 3")
(let ((list nil))
(handler-case (loop (push (read in) list))
(end-of-file ()
(nreverse list)))))
signature.asc

Zach Beane

unread,
Mar 28, 2015, 8:25:45 AM3/28/15
to
It's more common these days to use the stream object itself as EOF.

Zach

Madhu

unread,
Mar 29, 2015, 6:46:29 AM3/29/15
to

* Kaz Kylheku <201503270...@kylheku.com> :
Wrote on Fri, 27 Mar 2015 15:34:30 +0000 (UTC):

| (defun scan-numbers (str)
| (let ((*read-eval* nil)) ;; omit if you trust the input
| (with-input-from-string (s (catenate 'string str " x"))
| (read-delimited-list #\x s))))
|
| Ah fuck, that should be CONcatenate, of course! I can never remember
| that piece of language abuse.

Maybe then you'd prefer

(with-input-from-string (delim-stream " x")
(with-input-from-string (stream STR)
(with-open-stream (make-concatenated-stream stream delim-stream)
(read-delimited ...etc...

[If your implementation resources string-input-streams, this idiom of
chaining with-input-from-string may be preferable to:

(with-open-stream (stream
(make-concatenated-stream (make-string-input-stream ...)
(make-string-input-stream ...) ...)) ...etc...)
]---Madhu

WJ

unread,
Mar 29, 2015, 12:40:19 PM3/29/15
to
I broke your lines for you. Anyone who knows anything whatsoever
about Usenet knows that he must limit the length of his lines.
Perhaps you believe your google-masters and you don't even know
that this is Usenet.

Gauche Scheme:

(use srfi-42) ; list-ec

(call-with-input-string " 0 #f 2 0 nil "
(lambda (port) (list-ec (: n port) n)))

===>
(0 #f 2 0 nil)

Also works under Racket and Larceny, with this change:

(require srfi/42) ; Racket

(require 'srfi-42) ; Larceny

WJ

unread,
Mar 29, 2015, 12:57:36 PM3/29/15
to
Gauche Scheme:

(use srfi-1) ; unfold

(with-input-from-string " 0 #f 2 0 nil "
(lambda () (unfold eof-object? identity (lambda _ (read)) (read))))

===>
(0 #f 2 0 nil)


Also works under Racket, with this change:

(require srfi/1)

Marco Antoniotti

unread,
Mar 30, 2015, 5:08:37 AM3/30/15
to
On Saturday, March 28, 2015 at 1:25:45 PM UTC+1, Zach Beane wrote:
....

>
> It's more common these days to use the stream object itself as EOF.
>
> Zach

That's actually a cute idea. Thanks.

MA

WJ

unread,
Jun 18, 2016, 2:28:03 PM6/18/16
to
Why this is marked as abuse? It has been marked as abuse.
Report not abuse
OCaml:

#load "str.cma";;

List.map int_of_string (Str.split (Str.regexp "[ \t]+") " 0 2 0 1 ") ;;

===>
[0; 2; 0; 1]

--
"Anti-racism," Shamir writes, "is a denial of the autochthon's [native's] right
to decide his fate; a tool to separate Man from his native landscape. This
concept de-legitimizes objections to swamping a land with a flood of immigrants
and ruining the society's fabric."
www.theoccidentalobserver.net/authors/Connelly-Gaza2.html
0 new messages