From: Dave
Subject: how to replace a string into sequence
Date: 
Message-ID: <fqq1b.257816$Ny5.7903079@twister2.libero.it>
Dear lispers,

>(defun replace-string (str old new)
    (let* ((begins 0) 
           (exi 0))
        (loop 
            (setq exi (search old str :start2 begins))
            (if (not exi) 
                (return str))
            (setq str (concatenate 'STRING 
                          (subseq str 0 exi) new (subseq str (1+ exi))))
            (setq begins 
                (+ exi (length new))))))

>(replace-string "How,are,you?" "," " - ")

>"How - are - you?"


I have not found any function in order to reduce this code.
Does anyone have idea?

Thanks.
Dave

From: Joe Marshall
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <ptixhdbk.fsf@ccs.neu.edu>
"Dave" <·········@iol.it> writes:

> Dear lispers,
>
>>(defun replace-string (str old new)
>     (let* ((begins 0) 
>            (exi 0))
>         (loop 
>             (setq exi (search old str :start2 begins))
>             (if (not exi) 
>                 (return str))
>             (setq str (concatenate 'STRING 
>                           (subseq str 0 exi) new (subseq str (1+ exi))))
>             (setq begins 
>                 (+ exi (length new))))))
>
>>(replace-string "How,are,you?" "," " - ")
>
>>"How - are - you?"
>
>
> I have not found any function in order to reduce this code.
> Does anyone have idea?

Recursion is your friend here.  Also, factor out the act
of splitting the string at the old position.
From: Dave
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <opI1b.259671$Ny5.7961565@twister2.libero.it>
"Joe Marshall" <···@ccs.neu.edu> wrote:
> 
> Recursion is your friend here.  Also, factor out the act
> of splitting the string at the old position.
> 

Recursion is my enemy forever, :(
but now I will try.

Bye!
Dave
From: Joe Marshall
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <ptitg0zq.fsf@ccs.neu.edu>
"Dave" <·········@iol.it> writes:

> "Joe Marshall" <···@ccs.neu.edu> wrote:
>> 
>> Recursion is your friend here.  Also, factor out the act
>> of splitting the string at the old position.
>> 
>
> Recursion is my enemy forever, :(
> but now I will try.

Nah, recursion makes life easy for you.
You want to replace all occurrances of some string, right?

Well, if you only replace the *leftmost* occurrance, and get someone
else to do the rest, you're done, right?  And if there aren't any
occurrances, you're done.  

Paste those two parts together.  Now who is that someone else that'll
do the rest?  The program you just wrote.
From: John
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <opruj73xapfhfgdd@news.chello.no>
On Mon, 25 Aug 2003 12:23:21 -0400, Joe Marshall <···@ccs.neu.edu> wrote:

> "Dave" <·········@iol.it> writes:
>
>> "Joe Marshall" <···@ccs.neu.edu> wrote:
>>>
>
> Nah, recursion makes life easy for you.
> You want to replace all occurrances of some string, right?
>

I tend to agree that having to resort to recursion and loops is akward.
This is one case I would probaly go outside te ANSI library ad use 
regexp's.
Nearly all lisps support it so somthing like:

#+corman
(defmacro my_search ...)
(defmacro my_compile ...)
(defmacro my_macth ...)
#+cmu
...
#+allegro
...
#end

(my_search ...)

Why not do this once and for all? (share it...)
Regexps really save pagefulls of code when verifying user input, say.
(Try verifying a date with several legal formats input as a string.)

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
From: Marco Baringer
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <m2vfsplh5t.fsf@bese.it>
"Dave" <·········@iol.it> writes:

>>(defun replace-string (str old new)
>     (let* ((begins 0) 
>            (exi 0))
>         (loop 
>             (setq exi (search old str :start2 begins))
>             (if (not exi) 
>                 (return str))
>             (setq str (concatenate 'STRING 
>                           (subseq str 0 exi) new (subseq str (1+ exi))))
>             (setq begins 
>                 (+ exi (length new))))))

i think you would do well to learn about with-output-to-string.

try: [untested]

(defun replace-string (string old new)
  (with-output-to-string (replaced)
    (loop for offset below (length string)
          if (string= string old
                      :start1 offset
                      :end1 (min (+ offset (length old))
                                 (length string))
            do (princ new replaced)
          else 
            do (princ (aref string offset) replaced))))

or [also untested]:

(defun replace-string (string old new)
  (cl-ppcre:regex-replace-all (regex-quote old) string new))

(defun regex-quote (string)
  (with-output-to-string (quoted)
    (loop for char across string
          when (member char '(#\* #\? #\+ #\( #\) #\[ #\] #\\))
            do (princ #\\ quoted)
          do (princ char quoted))))

-- 
-Marco
Ring the bells that still can ring.
Forget your perfect offering.
There is a crack in everything.
That's how the light gets in.
     -Leonard Cohen
From: Pascal Bourguignon
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <87isoo5zy6.fsf@thalassa.informatimago.com>
"Dave" <·········@iol.it> writes:

> Dear lispers,
> 
> >(defun replace-string (str old new)
>     (let* ((begins 0) 
>            (exi 0))
>         (loop 
>             (setq exi (search old str :start2 begins))
>             (if (not exi) 
>                 (return str))
>             (setq str (concatenate 'STRING 
>                           (subseq str 0 exi) new (subseq str (1+ exi))))
>             (setq begins 
>                 (+ exi (length new))))))
> 
> >(replace-string "How,are,you?" "," " - ")
> 
> >"How - are - you?"
> 
> 
> I have not found any function in order to reduce this code.
> Does anyone have idea?

I would use:

    (defun replace-string (str old new)
       (unsplit-string (split-string str (regexp-quote old)) new))

But then split-string and unsplit-string may be untrivial...



I find it more efficient to concatenate once at then end, keeping chunks:

(defun replace-string (str old new)
    (do* ((start 0 (1+ p))
          (p (if (< start (length str)) (search old str :start2 start))
             (if (< start (length str)) (search old str :start2 start)))
          (newstr '()))
        ((null p) 
         (progn (push (subseq str start p) newstr)
                (apply (function concatenate) 'string (nreverse newstr))))
     (push (subseq str start p) newstr)
     (push new newstr))
    )

It would be  even better to keep only ranges,  and then allocating and
copying once at the end.


-- 
__Pascal_Bourguignon__                   http://www.informatimago.com/
----------------------------------------------------------------------
Do not adjust your mind, there is a fault in reality.
From: Steve Long
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <BB6CEF07.45A5%sal6741@hotmail.com>
On 08/22/2003 8:13 AM, in article
························@twister2.libero.it, "Dave" <·········@iol.it>
wrote:

> Dear lispers,
> 
>> (defun replace-string (str old new)
>   (let* ((begins 0)
>          (exi 0))
>       (loop 
>           (setq exi (search old str :start2 begins))
>           (if (not exi)
>               (return str))
>           (setq str (concatenate 'STRING
>                         (subseq str 0 exi) new (subseq str (1+ exi))))
>           (setq begins
>               (+ exi (length new))))))
> 
>> (replace-string "How,are,you?" "," " - ")
> 
>> "How - are - you?"
> 
> 
> I have not found any function in order to reduce this code.
> Does anyone have idea?
> 
> Thanks.
> Dave
> 


No doubt, someone will have answered this by the time my message is posted,
but I gen'd this up jiffy quick in MCL...

(defun string-substitute (old-str new-str string &key (ignore-case? nil))
  (do* ((test        (if ignore-case? #'char-equal #'char=))
        (len-old-str (length old-str))
        (string-out  ""
                     (concatenate
                      'string
                      string-out
                      (subseq str 0 p)
                      new-str))
        (str         string
                     (subseq str (+ p len-old-str)))
        (p           (search old-str str :test test)
                     (search old-str str :test test)))
       ((null p) (concatenate 'string string-out str))))

This is a verbose example designed to illustrate the "parts" of the
solution. The principal inefficiency is in the intermediate concatenations,
which could be replaced with list push operations and a FINAL string conc'n.

S Long
From: Russell Senior
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <86oeyel78g.fsf@coulee.tdb.com>
>>>>> "Dave" == Dave  <·········@iol.it> writes:

> (replace-string "How,are,you?" "," " - ")

> "How - are - you?"

Dave> I have not found any function in order to reduce this code.
Dave> Does anyone have idea?

I wrote a facility to do this sort of thing a few months ago.  I
haven't given it a final polish, but it is mostly there.  

I use a generic function REPLACE-ALL with methods that work on
string-to-string, char-to-char, string-to-char and char-to-string
replacements.  In order to reduce lots of string allocations, I use a
<COMPOUND-STRING> object that maintains a list of strings and then a
string specificaion, a list of descriptions of source-string, start
and end indices.  If a REPLACE-ALL can be done in place, it does.
Otherwise, it constructs one of these <COMPOUND-STRING> objects.  A
call to the CONDENSE function at the end allocates, fills according to
the string specification, and returns a newly allocated string.

I don't know how this stacks up, efficiency-wise, with other methods.
The goal was to avoid unnecessary allocation, particularly where
REPLACE-ALL would be called multiple times with different arguments.

See:

  <http://www.aracnet.com/~seniorr/string-manipulation.lisp>

> (condense (replace-all "How,are,you?" "," " - "))
"How - are - you?"

Comments, suggestions, improvements welcome.

-- 
Russell Senior         ``shtal latta wos ba padre u prett tu nashtonfi
·······@aracnet.com      mrlosh''  -- Bashgali Kafir for ``If you have
                         had diarrhoea many days you will surely die.''
From: Dennis Decker Jensen
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <eb3555d9.0308261202.10f88893@posting.google.com>
"Dave" <·········@iol.it> wrote in message news:<························@twister2.libero.it>...
> >(defun replace-string (str old new)
>     (let* ((begins 0) 
>            (exi 0))
>         (loop 
>             (setq exi (search old str :start2 begins))
>             (if (not exi) 
>                 (return str))
>             (setq str (concatenate 'STRING 
>                           (subseq str 0 exi) new (subseq str (1+ exi))))
>             (setq begins 
>                 (+ exi (length new))))))
> 
> >(replace-string "How,are,you?" "," " - ")
>  
> >"How - are - you?"
> 
> I have not found any function in order to reduce this code.
> Does anyone have idea?

Unlike the above code, the code below doesn't modify the original
string. Is that a requirement?

(defun replace-string (new old str)
  (let ((next (search old str)))
    (if (or (null next)(string= old "")) str
        (concatenate 'STRING (subseq str 0 next) new
                     (replace-string
                       new old (subseq str (+ next (length old))))))))

You state somewhere else in this thread that recursion isn't your
deal, but I couldn't see any other way to reduce the code. The number
of concatenations is the same as the number of substitutions, so
unless you need to do thousands of replacements in a huge string, I
don't think you'll run into trouble: Profile the code.

--
Dennis Decker Jensen
From: Wolfhard Buß
Subject: Re: how to replace a string into sequence
Date: 
Message-ID: <m3znhwiorh.fsf@buss-14250.user.cis.dfn.de>
Dave writes:
>  
> (defun replace-string (str old new)

 (defun supersede (new-seq old-seq sequence)
   (let ((result-type (result-type (type-of sequence)))
         (old-seq-length (length old-seq)))
     (labels ((%supersede (replaced rest)
                (let ((start (search old-seq rest)))
                  (if start
                      (%supersede (concatenate result-type replaced (subseq rest 0 start) new-seq)
                                  (subseq rest (+ start old-seq-length)))
                      (concatenate result-type replaced rest)))))
       (if (zerop old-seq-length)
           (coerce sequence result-type)
           (%supersede (make-sequence result-type 0) sequence)))))

 (defun supplant (doctor sequence)
   (let ((result-type (result-type (type-of sequence))))
     (labels ((%supplant (replaced rest)
                (multiple-value-bind (start end new-seq) (funcall doctor rest)
                  ;; Lispniks know what the doctors function is.
                  (if start
                      (%supplant (concatenate result-type replaced (subseq rest 0 start) new-seq)
                                 (subseq rest end))
                      (concatenate result-type replaced rest)))))
     (%supplant (make-sequence result-type 0) sequence))))

Efficiency is left as an exercise. Busy Lispnik might even find
nsupersede or nsupplant, or something else.

-- 
"Hurry if you still want to see something. Everything is vanishing."
                                       --  Paul C�zanne (1839-1906)