@@ -700,12 +700,11 @@ _free_pat_replacer(x) = nothing
700700_pat_replacer (x:: AbstractChar ) =  isequal (x)
701701_pat_replacer (x:: Union{Tuple{Vararg{AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}} ) =  in (x)
702702
703- function   replace (str :: String , pat_repl :: Vararg{Pair,N} ; count :: Integer = typemax (Int))  where  N 
704-      count  ==   0   &&   return  str 
703+ #  note: leave str untyped here to make it easier for packages like StringViews to hook in 
704+ function   _replace_init (str, pat_repl :: NTuple{N, Pair} ,  count:: Int )  where  N 
705705    count <  0  &&  throw (DomainError (count, " `count` must be non-negative." 
706-     n =  1 
707-     e1 =  nextind (str, lastindex (str)) #  sizeof(str)
708-     i =  a =  firstindex (str)
706+     e1 =  nextind (str, lastindex (str)) #  sizeof(str)+1
707+     a =  firstindex (str)
709708    patterns =  map (p ->  _pat_replacer (first (p)), pat_repl)
710709    replaces =  map (last, pat_repl)
711710    rs =  map (patterns) do  p
@@ -716,21 +715,24 @@ function replace(str::String, pat_repl::Vararg{Pair,N}; count::Integer=typemax(I
716715        r isa  Int &&  (r =  r: r) #  findnext / performance fix
717716        return  r
718717    end 
719-     if  all (> (e1), map (first, rs))
720-         foreach (_free_pat_replacer, patterns)
721-         return  str
722-     end 
723-     out =  IOBuffer (sizehint= floor (Int, 1.2 sizeof (str)))
718+     return  e1, patterns, replaces, rs, all (> (e1), map (first, rs))
719+ end 
720+ 
721+ #  note: leave str untyped here to make it easier for packages like StringViews to hook in
722+ function  _replace_finish (io:: IO , str, count:: Int ,
723+                          e1:: Int , patterns:: Tuple , replaces:: Tuple , rs:: Tuple )
724+     n =  1 
725+     i =  a =  firstindex (str)
724726    while  true 
725727        p =  argmin (map (first, rs)) #  TODO : or argmin(rs), to pick the shortest first match ?
726728        r =  rs[p]
727729        j, k =  first (r), last (r)
728730        j >  e1 &&  break 
729731        if  i ==  a ||  i <=  k
730732            #  copy out preserved portion
731-             GC. @preserve  str unsafe_write (out , pointer (str, i), UInt (j- i))
733+             GC. @preserve  str unsafe_write (io , pointer (str, i), UInt (j- i))
732734            #  copy out replacement string
733-             _replace (out , replaces[p], str, r, patterns[p])
735+             _replace (io , replaces[p], str, r, patterns[p])
734736        end 
735737        if  k <  j
736738            i =  j
@@ -755,13 +757,39 @@ function replace(str::String, pat_repl::Vararg{Pair,N}; count::Integer=typemax(I
755757        n +=  1 
756758    end 
757759    foreach (_free_pat_replacer, patterns)
758-     write (out, SubString (str, i))
759-     return  String (take! (out))
760+     write (io, SubString (str, i))
761+     return  io
762+ end 
763+ 
764+ #  note: leave str untyped here to make it easier for packages like StringViews to hook in
765+ function  _replace_ (io:: IO , str, pat_repl:: NTuple{N, Pair} , count:: Int ) where  N
766+     if  count ==  0 
767+         write (io, str)
768+         return  io
769+     end 
770+     e1, patterns, replaces, rs, notfound =  _replace_init (str, pat_repl, count)
771+     if  notfound
772+         foreach (_free_pat_replacer, patterns)
773+         write (io, str)
774+         return  io
775+     end 
776+     return  _replace_finish (io, str, count, e1, patterns, replaces, rs)
760777end 
761778
779+ #  note: leave str untyped here to make it easier for packages like StringViews to hook in
780+ function  _replace_ (str, pat_repl:: NTuple{N, Pair} , count:: Int ) where  N
781+     count ==  0  &&  return  str
782+     e1, patterns, replaces, rs, notfound =  _replace_init (str, pat_repl, count)
783+     if  notfound
784+         foreach (_free_pat_replacer, patterns)
785+         return  str
786+     end 
787+     out =  IOBuffer (sizehint= floor (Int, 1.2 sizeof (str)))
788+     return  String (take! (_replace_finish (out, str, count, e1, patterns, replaces, rs)))
789+ end 
762790
763791""" 
764-     replace(s::AbstractString, pat=>r, [pat2=>r2, ...]; [count::Integer]) 
792+     replace([io::IO],  s::AbstractString, pat=>r, [pat2=>r2, ...]; [count::Integer]) 
765793
766794Search for the given pattern `pat` in `s`, and replace each occurrence with `r`. 
767795If `count` is provided, replace at most `count` occurrences. 
@@ -774,13 +802,21 @@ If `pat` is a regular expression and `r` is a [`SubstitutionString`](@ref), then
774802references in `r` are replaced with the corresponding matched text. 
775803To remove instances of `pat` from `string`, set `r` to the empty `String` (`""`). 
776804
805+ The return value is a new string after the replacements.  If the `io::IO` argument 
806+ is supplied, the transformed string is instead written to `io` (returning `io`). 
807+ (For example, this can be used in conjunction with an [`IOBuffer`](@ref) to re-use 
808+ a pre-allocated buffer array in-place.) 
809+ 
777810Multiple patterns can be specified, and they will be applied left-to-right 
778811simultaneously, so only one pattern will be applied to any character, and the 
779812patterns will only be applied to the input text, not the replacements. 
780813
781814!!! compat "Julia 1.7" 
782815    Support for multiple patterns requires version 1.7. 
783816
817+ !!! compat "Julia 1.10" 
818+     The `io::IO` argument requires version 1.10. 
819+ 
784820# Examples 
785821```jldoctest 
786822julia> replace("Python is a programming language.", "Python" => "Julia") 
@@ -799,8 +835,12 @@ julia> replace("abcabc", "a" => "b", "b" => "c", r".+" => "a")
799835"bca" 
800836``` 
801837""" 
838+ replace (io:: IO , s:: AbstractString , pat_f:: Pair... ; count= typemax (Int)) = 
839+     _replace_ (io, String (s), pat_f, Int (count))
840+ 
802841replace (s:: AbstractString , pat_f:: Pair... ; count= typemax (Int)) = 
803-     replace (String (s), pat_f... , count= count)
842+     _replace_ (String (s), pat_f, Int (count))
843+ 
804844
805845#  TODO : allow transform as the first argument to replace?
806846
0 commit comments