# substitute

Definition: | sequence text = substitute(sequence text, object s, r, integer limit=-1)
Description: | Replace at most limit instances, or all if limit is -1, of s in text with r. s and r can be strings or individual characters (or one of each).
pwa/p2js: | Supported.
Comments: | Ideal for extensive text manipulation, eg re-indenting html or stripping tags to leave plain text. Very long strings that need thousands of replacements are broken up into thousands of chunks and re-assembled once at the end, which makes this far more efficient than an "in situ" operation, since individual characters (in particular the last few) are moved just twice rather than thousands of times. The Euphoria match_replace() routine offers similar but less efficient functionality, especially when the lengths of s and r differ. The previous replace_all() routine of Euphoria has been deprecated in favour of match_replace(). The Phix implementation of substitute() as found in builtins\substitute.e and reproduced below should work on Euphoria, once all the string types are replaced with sequence types.
Example: |
    ?substitute("abracadabra", "ra", "X")       -- displays "abXcadabX"
    ?substitute("abracadabra", "a", "")         -- displays "brcdbr"
Implementation: | See builtins\substitute.e (an autoinclude), reproduced in the technicalia dropdown below, for details of the actual implementation.
See Also: | join, tagset
Technicalia | I have reproduced this routine here because I think it is interesting to study, especially since it can in some cases prove to be several thousand times faster than a simpler/in situ method.
    global function substitute(sequence text, object s, r, integer limit=-1)
    -- replace all instances of s in text with r
        integer k = 1,
                l = iff(atom(s)?1:length(s)),
                startidx = 1
        sequence chunks = {}
        while limit=-1 or length(chunks)<limit do
            k = match(s,text,k)
            if k=0 then exit end if
            chunks = append(chunks,text[startidx..k-1])
            k += l
            startidx = k
        end while
        if length(chunks) then
            chunks = append(chunks,text[startidx..$])
            text = chunks[1]
            for i=2 to length(chunks) do
                text &= r
                text &= chunks[i]
            end for
        end if
        return text
    end function
Originally text/r/s were string, and that remains the primary use case, however I did once find a need for sequences, when investigating runs of differences in the sequence/generation of safe numbers. I should note that the replacement had to be nested one more than I first expected, because of the `text &= r`, not always behaving quite the same as the `text[s..e] = r` it logically replaces, that is when r is not a string. Likewise I changed the first parameter/return of substitute_all() to a sequence.