• Re: Beginner code - splitting lines on whitespace

    From B. Pym@Nobody447095@here-nor-there.org to comp.lang.lisp on Fri Aug 8 09:30:46 2025
    From Newsgroup: comp.lang.lisp

    Ken Tilton wrote:

    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. :)


    Gauche Scheme

    (use srfi-13) ;; string-tokenize

    (with-input-from-string
    "mach1 host1 /home/me
    mach2 host2 /export/home/me
    mach3 host3 c:\\home\\me"
    (lambda()
    (generator-map string-tokenize read-line)))

    (("mach1" "host1" "/home/me")
    ("mach2" "host2" "/export/home/me")
    ("mach3" "host3" "c:\\home\\me"))
    --
    The good news is, it's not Lisp that sucks, but Common Lisp. --- Paul Graham --- Synchronet 3.21a-Linux NewsLink 1.2