@@ -681,8 +681,8 @@ _free_pat_replacer(x) = nothing
681681_pat_replacer (x:: AbstractChar ) = isequal (x)
682682_pat_replacer (x:: Union{Tuple{Vararg{AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}} ) = in (x)
683683
684- function replace (str :: String , pat_repl :: Vararg{Pair,N} ; count :: Integer = typemax (Int)) where N
685- count == 0 && return str
684+ # note: leave str untyped here to make it easier for packages like StringViews to hook in
685+ function _replace_init (str, pat_repl :: NTuple{N, Pair} , count:: Int ) where N
686686 count < 0 && throw (DomainError (count, " `count` must be non-negative." ))
687687 n = 1
688688 e1 = nextind (str, lastindex (str)) # sizeof(str)
@@ -697,11 +697,11 @@ function replace(str::String, pat_repl::Vararg{Pair,N}; count::Integer=typemax(I
697697 r isa Int && (r = r: r) # findnext / performance fix
698698 return r
699699 end
700- if all (> (e1), map (first, rs))
701- foreach (_free_pat_replacer, patterns)
702- return str
703- end
704- out = IOBuffer (sizehint = floor ( Int, 1.2 sizeof (str)))
700+ return patterns, replaces, rs, all (> (e1), map (first, rs))
701+ end
702+
703+ # note: leave str untyped here to make it easier for packages like StringViews to hook in
704+ function _replace_finish ( out:: IO , str, count :: Int , patterns :: NTuple{N} , replaces :: NTuple{N} , rs) where N
705705 while true
706706 p = argmin (map (first, rs)) # TODO : or argmin(rs), to pick the shortest first match ?
707707 r = rs[p]
@@ -737,12 +737,34 @@ function replace(str::String, pat_repl::Vararg{Pair,N}; count::Integer=typemax(I
737737 end
738738 foreach (_free_pat_replacer, patterns)
739739 write (out, SubString (str, i))
740- return String (take! (out))
740+ return out
741+ end
742+
743+ # note: leave str untyped here to make it easier for packages like StringViews to hook in
744+ function _replace_io (out:: IO , retval, str, pat_repl:: Pair... ; count:: Integer = typemax (Int))
745+ count == 0 && return out
746+ patterns, replaces, rs, notfound = _replace_init (str, pat_repl, count)
747+ if notfound
748+ foreach (_free_pat_replacer, patterns)
749+ return out
750+ end
751+ return _replace_finish (out, str, count, patterns, replaces, rs)
741752end
742753
754+ # note: leave str untyped here to make it easier for packages like StringViews to hook in
755+ function _replace_str (str, pat_repl:: Pair... ; count:: Integer = typemax (Int))
756+ count == 0 && return str
757+ patterns, replaces, rs, notfound = _replace_init (str, pat_repl, count)
758+ if notfound
759+ foreach (_free_pat_replacer, patterns)
760+ return str
761+ end
762+ out = IOBuffer (sizehint= floor (Int, 1.2 sizeof (str)))
763+ return String (take! (_replace_finish (out, str, count, patterns, replaces, rs)))
764+ end
743765
744766"""
745- replace(s::AbstractString, pat=>r, [pat2=>r2, ...]; [count::Integer])
767+ replace([out::IO], s::AbstractString, pat=>r, [pat2=>r2, ...]; [count::Integer])
746768
747769Search for the given pattern `pat` in `s`, and replace each occurrence with `r`.
748770If `count` is provided, replace at most `count` occurrences.
@@ -755,13 +777,21 @@ If `pat` is a regular expression and `r` is a [`SubstitutionString`](@ref), then
755777references in `r` are replaced with the corresponding matched text.
756778To remove instances of `pat` from `string`, set `r` to the empty `String` (`""`).
757779
780+ The return value is a new string with the replacements. If the `out::IO` argument
781+ is supplied, the transformed string is instead written to `out` (returning `out`).
782+ (For example, this can be used in conjunction with [`IOBuffer`](@ref) to re-use
783+ an pre-allocated buffer array in-place.)
784+
758785Multiple patterns can be specified, and they will be applied left-to-right
759786simultaneously, so only one pattern will be applied to any character, and the
760787patterns will only be applied to the input text, not the replacements.
761788
762789!!! compat "Julia 1.7"
763790 Support for multiple patterns requires version 1.7.
764791
792+ !!! compat "Julia 1.10"
793+ The `out::IO` argument requires version 1.10.
794+
765795# Examples
766796```jldoctest
767797julia> replace("Python is a programming language.", "Python" => "Julia")
@@ -780,8 +810,18 @@ julia> replace("abcabc", "a" => "b", "b" => "c", r".+" => "a")
780810"bca"
781811```
782812"""
813+ replace (out:: IO , s:: AbstractString , pat_f:: Pair... ; count= typemax (Int)) =
814+ _replace_io (out, String (s), pat_f... , count= count)
815+
783816replace (s:: AbstractString , pat_f:: Pair... ; count= typemax (Int)) =
784- replace (String (s), pat_f... , count= count)
817+ _replace_str (String (s), pat_f... , count= count)
818+
819+ # no copy needed for SubString{String}
820+ replace (out:: IO , s:: SubString{String} , pat_f:: Pair... ; count= typemax (Int)) =
821+ _replace_io (out, s, pat_f... , count= count)
822+ replace (s:: SubString{String} , pat_f:: Pair... ; count= typemax (Int)) =
823+ _replace_str (s, pat_f... , count= count)
824+
785825
786826# TODO : allow transform as the first argument to replace?
787827
0 commit comments