• Re: Beginner code - splitting lines on whitespace

    From B. Pym@21:1/5 to All on Sat Jul 20 08:56:27 2024
    (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))

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From B. Pym@21:1/5 to B. Pym on Mon Jul 22 13:25:51 2024
    B. Pym wrote:

    (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))

    Another way.

    Gauche Scheme

    (use srfi-13) ;; string ops.
    (use gauche.generator)

    (define (white-space? c) (member c '(#\space #\tab)))

    (define (make-token-generator str)
    (let ((str str)
    (start 0)
    (end 0))
    (lambda ()
    (set! start
    (and start end (string-skip str white-space? end)))
    (if start
    (begin
    (set! end (string-index str white-space? start))
    (string-copy str start end))
    (eof-object)))))

    (define (split-on-space str)
    (generator->list (make-token-generator str)))

    (split-on-space "")
    ===>
    ()

    (split-on-space " ")
    ===>
    ()

    (split-on-space "foo")
    ===>
    ("foo")

    (split-on-space " foo ")
    ===>
    ("foo")

    (split-on-space " foo bar ")
    ===>
    ("foo" "bar")

    (split-on-space " 3.14 foo? [bar] ")
    ===>
    ("3.14" "foo?" "[bar]")

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From B. Pym@21:1/5 to Ken Tilton on Fri Aug 8 09:30:46 2025
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)