(defun white-space-p (c)
(or (char= c #\Space) (char= c #\Tab)))
(defun split-on-space (string)
(loop
for b = (position-if-not #'white-space-p string)
then (position-if-not #'white-space-p string :start e)
for e = (when b (position-if #'white-space-p string :start b))
while b
collect (subseq string b e)
while e))
(defun white-space-p (c)
(or (char= c #\Space) (char= c #\Tab)))
(defun split-on-space (string)
(loop
for b = (position-if-not #'white-space-p string)
then (position-if-not #'white-space-p string :start e)
for e = (when b (position-if #'white-space-p string :start b))
while b
collect (subseq string b e)
while e))
Gauche Scheme
(use srfi-13) ;; string ops.
(define (white-space? c) (member c '(#\space #\tab)))
(define (split-on-space str :optional (start 0))
(let1 b (and start (string-skip str white-space? start))
(if b
(let1 e (string-index str white-space? b)
(cons (string-copy str b e) (split-on-space str e)))
'())))
(split-on-space " foo bar ")
===>
("foo" "bar")
(split-on-space "foo")
===>
("foo")
(split-on-space "")
===>
()
Another way:
(define-method object-apply ((s <string>) (i <integer>) j)
(string-copy s i j))
(define (split-on-space str :optional (start 0))
(let1 b (and start (string-skip str white-space? start))
(if b
(let1 e (string-index str white-space? b)
(cons (str b e) (split-on-space str e)))
'())))
The easy way.
(use srfi-13)
(define (split-on-space str)
(string-tokenize str))
Steve Allan wrote:
I've been lurking here for a bit, and trying to learn lisp in my spare time. As an exercise, I'm trying to port some Perl code to lisp, and
the first bit of functionality I wrote was to read a file that looks
like this:
#------------------------------------------
# unique-label hostname home-dir #------------------------------------------
mach1 host1 /home/me
mach2 host2 /export/home/me
mach3 host3 c:\\home\\me
And split each line into a list, returning a list of lists:
(("mach1" "host1" "/home/me")
("mach2" "host2" "/export/home/me")
("mach3" "host3" "c:\\home\\me"))
The code below does this, but I'm pretty sure there's much that could
be improved. To speed up my learning, I'd love feedback in either/both
of these areas.
1) Critique on the implementation - how to improve the code as
written.
2) Suggestions for a better approach altogether.
I realize the task I'm coding is pretty mundane, but I think I could
learn a lot of the basics by really getting this right, so your
critique would be most welcome.
Thanks!
Code is below.
--
-- Steve
;;;;================================================================
(defun get-platforms (file)
(with-open-file (platforms file)
(loop for line = (read-line platforms nil)
while line
unless (position #\# line)
collect (split-on-space line))))
(defun split-on-space (string)
"Splits string on whitespace, meaning spaces and tabs"
(unless (null string)
(let ((space (or (position #\space string) (position #\tab string))))
(cond
(space (cons
(subseq string 0 space)
(split-on-space
(string-trim '(#\Space #\Tab) (subseq string space)))))
(t (list string))))))
Not bad at all. (unless (null x)...) should be (when x...) I think you
might agree. You might avoid searching the string twice, one for tab and
once for space, by using position-if. And a lot of us have little macros
akin to Paul Graham's AIF. I have (untested):
(when string
(bif (delim-pos (position-if (lambda (c)
(or (char= c #\space)(char= c #\tab)))
string))
(cons (subseq string 0 delim-pos) ...etc...)
(list string))
BIF left as an exercise. :)
| Sysop: | Keyop |
|---|---|
| Location: | Huddersfield, West Yorkshire, UK |
| Users: | 715 |
| Nodes: | 16 (2 / 14) |
| Uptime: | 05:38:18 |
| Calls: | 12,100 |
| Calls today: | 8 |
| Files: | 15,003 |
| Messages: | 6,517,909 |
| Posted today: | 1 |