Hi!
I just finished an exercise from [K&R2] which is supposed to return a list
of words in passed string. I would really appreciate it if someone could
look at it and maybe give me some pointers on how I can improve it's
efficiency or ellegance (or both). I would also like to know if anyone has
written one such function using functional style (I couldn't figure out how
to do it that way).
[K&R2] If you don't know, it's 'The C Programming Language' by Kernigham
and Ritchie
;;;
;;; A "word" is defined as the sequence of characters separated
;;; by space, tab, newline, or EOL (End Of Line);
;;;
(defun parse-string (str)
"Returns a list of words in string STR."
(labels ((spacep (ch)
(or (equal ch #\Space)
(equal ch #\Newline)
(equal ch #\Tab))))
(when (stringp str)
(let ((word '()) (words '()))
(dovector (ch str)
(if (spacep ch)
(progn (setf words (append words (list (coerce word 'string))))
(setf word '()))
(setf word (append word (list ch)))))
(setf words (append words (list (coerce word 'string))))
(return-from parse-string words)))))
Thanks in advance,
rk
--
Richard Krushelnitskiy "A mathematician is a blind man in a dark
·········@gmx.net room looking for a black cat which isn't
http://rkrush.cjb.net there." -- Charles Darwin
> I just finished an exercise from [K&R2] which is supposed to return a list
> of words in passed string. I would really appreciate it if someone could
> look at it and maybe give me some pointers on how I can improve it's
> efficiency or ellegance (or both). I would also like to know if anyone has
> written one such function using functional style (I couldn't figure out how
> to do it that way).
I did something similar;
(defmacro trimstring (str)
`(string-trim '(#\Space #\Tab #\Newline) ,str))
(defun unstringify-into-list (words)
(let ((wlist nil))
(loop for i = (position #\Space words)
until (= (length words) 0)
do
(push (trimstring (if i
(subseq words 0 i)
; else
words))
wlist)
(setf words (if i
(trimstring (subseq words i))
;else
"")))
(nreverse wlist)))
- but I'm not sure if its very good. Its worked OK so far, though I
think it should also split words on #\Tab and #\Newline instead of
just #\Space.
Gregm
Hello!
In article <··············@europa.mindspring.com>,
Greg Menke <··········@mindspring.com> wrote:
>(defmacro trimstring (str)
> `(string-trim '(#\Space #\Tab #\Newline) ,str))
No need for a macro here.
(declaim (inline trimstring))
(defun trimstring (str)
(string-trim '(#\Space #\Tab #\Newline) str))
>(defun unstringify-into-list (words)
> (let ((wlist nil))
> (loop for i = (position #\Space words)
> until (= (length words) 0)
> do
> (push (trimstring (if i
> (subseq words 0 i)
> ; else
> words))
> wlist)
> (setf words (if i
> (trimstring (subseq words i))
> ;else
> "")))
> (nreverse wlist)))
You could use loop's collect clause for collecting the words instead
of the (push ...) action:
(defun unstringify-into-list (words)
(loop for i = (position #\Space words)
until (= (length words) 0)
collect (trimstring (if i (subseq words 0 i)
words))
do (setf words (if i (trimstring (subseq words i))
""))))
>- but I'm not sure if its very good. Its worked OK so far, though I
> think it should also split words on #\Tab and #\Newline instead of
> just #\Space.
Yes, that'd be another improvement, also to be applied to my code.
Something like (position-if #'whitespace-p words) with an appropriate
definition of function whitespace-p.
Also, we could not cons intermediate strings (setf words ...), instead
just keeping current indices. The :start keyword parameter for
position(-if) helps.
Kind regards,
Hannah.
>
> >(defmacro trimstring (str)
> > `(string-trim '(#\Space #\Tab #\Newline) ,str))
>
> No need for a macro here.
Its used elsewhere too, and whatever calling overhead it imposes has
no other benefit...
> >- but I'm not sure if its very good. Its worked OK so far, though I
> > think it should also split words on #\Tab and #\Newline instead of
> > just #\Space.
>
> Yes, that'd be another improvement, also to be applied to my code.
>
> Something like (position-if #'whitespace-p words) with an appropriate
> definition of function whitespace-p.
>
> Also, we could not cons intermediate strings (setf words ...), instead
> just keeping current indices. The :start keyword parameter for
> position(-if) helps.
>
> Kind regards,
>
> Hannah.
Thanks, another reader of this newsgroup emailed me with a similarly
improved version.
Gregm
Richard Krush <·········@gmx.net> writes:
> Hi!
>
> I just finished an exercise from [K&R2] which is supposed to return a list
> of words in passed string. I would really appreciate it if someone could
> look at it and maybe give me some pointers on how I can improve it's
> efficiency or ellegance (or both). I would also like to know if anyone has
> written one such function using functional style (I couldn't figure out how
> to do it that way).
>
> [K&R2] If you don't know, it's 'The C Programming Language' by Kernigham
> and Ritchie
>
> ;;;
> ;;; A "word" is defined as the sequence of characters separated
> ;;; by space, tab, newline, or EOL (End Of Line);
> ;;;
> (defun parse-string (str)
> "Returns a list of words in string STR."
> (labels ((spacep (ch)
> (or (equal ch #\Space)
> (equal ch #\Newline)
> (equal ch #\Tab))))
> (when (stringp str)
> (let ((word '()) (words '()))
> (dovector (ch str)
> (if (spacep ch)
> (progn (setf words (append words (list (coerce word 'string))))
> (setf word '()))
> (setf word (append word (list ch)))))
> (setf words (append words (list (coerce word 'string))))
> (return-from parse-string words)))))
You'll find plenty of examples by using for example this query:
http://groups.google.com/groups?as_q="split-string"&as_ugroup=comp.lang.lisp&num=50
On your particular example a few comments:
- Collecting stuff by appending the new values to the end of the list
is wasteful. A more common usage is adding them to the beginning of
the list by PUSH etc, and reversing the finished list with REVERSE
or NREVERSE.
- Using lists to collect the characters of the word one by one is
unnecessary, you can use CL's sequence functions like POSITION and
SUBSEQ.
--