Re: string substitution?



georgeryoung@xxxxxxxxx wrote:
I recently tried to do a seemingly simple thing and could not see how.
Given a string, I wanted to substitute a CR-LF for each LF, or if you
prefer, insert a CR before each LF. I'm sure it can be done with some
crufty characater by character loop, but it seems like there should be
an elegant solution.

Strings are sequences. Let's make one with a LF in it:
CL-USER> (defparameter lf-string (concatenate 'string "foo" (string
#\Return)))
LF-STRING
CL-USER> lf-string
"foo^M"

So, you want to replace one element in a sequence with two elements.
You have map, which can apply a function to every element in a
sequence, and return a new sequence with the result, so replacing
that LF with something else is easy:
CL-USER> (map 'string (lambda (e)
(if (eql e #\Return)
#\x
e))
lf-string)
"foox"

We need something like that, but something that can handle more
than one return value. Let's build it:
(defun map-values (result-type function first-sequence)
(let ((new-seq ()))
(loop for e across first-sequence do
(dolist (v (multiple-value-list (funcall function e)))
(push v new-seq)))
(map result-type #'identity (nreverse new-seq))))

Now we can say this:
CL-USER> (map-values 'string (lambda (e)
(if (eql e #\Return)
(values #\Newline #\Return)
e))
lf-string)
"foo
^M"

Which I believe is what you wanted? I'm fairly new to CL myself,
so there might be an easier way. Still, this is trivial and a
general solution (I think, haven't tested it much).

.