@@ -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,12 @@ 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 ,
705+ patterns:: NTuple{N} , replaces:: NTuple{N} , rs:: NTuple{N} ) where N
705706 while true
706707 p = argmin (map (first, rs)) # TODO : or argmin(rs), to pick the shortest first match ?
707708 r = rs[p]
@@ -737,12 +738,38 @@ function replace(str::String, pat_repl::Vararg{Pair,N}; count::Integer=typemax(I
737738 end
738739 foreach (_free_pat_replacer, patterns)
739740 write (out, SubString (str, i))
740- return String ( take! ( out))
741+ return out
741742end
742743
744+ # note: leave str untyped here to make it easier for packages like StringViews to hook in
745+ function _replace_io (out:: IO , retval, str, pat_repl:: Pair... ; count:: Integer = typemax (Int))
746+ if count == 0
747+ write (out, str)
748+ return out
749+ end
750+ patterns, replaces, rs, notfound = _replace_init (str, pat_repl, count)
751+ if notfound
752+ foreach (_free_pat_replacer, patterns)
753+ write (out, str)
754+ return out
755+ end
756+ return _replace_finish (out, str, count, patterns, replaces, rs)
757+ end
758+
759+ # note: leave str untyped here to make it easier for packages like StringViews to hook in
760+ function _replace_str (str, pat_repl:: Pair... ; count:: Integer = typemax (Int))
761+ count == 0 && return str
762+ patterns, replaces, rs, notfound = _replace_init (str, pat_repl, count)
763+ if notfound
764+ foreach (_free_pat_replacer, patterns)
765+ return str
766+ end
767+ out = IOBuffer (sizehint= floor (Int, 1.2 sizeof (str)))
768+ return String (take! (_replace_finish (out, str, count, patterns, replaces, rs)))
769+ end
743770
744771"""
745- replace(s::AbstractString, pat=>r, [pat2=>r2, ...]; [count::Integer])
772+ replace([out::IO], s::AbstractString, pat=>r, [pat2=>r2, ...]; [count::Integer])
746773
747774Search for the given pattern `pat` in `s`, and replace each occurrence with `r`.
748775If `count` is provided, replace at most `count` occurrences.
@@ -755,13 +782,21 @@ If `pat` is a regular expression and `r` is a [`SubstitutionString`](@ref), then
755782references in `r` are replaced with the corresponding matched text.
756783To remove instances of `pat` from `string`, set `r` to the empty `String` (`""`).
757784
785+ The return value is a new string after the replacements. If the `out::IO` argument
786+ is supplied, the transformed string is instead written to `out` (returning `out`).
787+ (For example, this can be used in conjunction with an [`IOBuffer`](@ref) to re-use
788+ a pre-allocated buffer array in-place.)
789+
758790Multiple patterns can be specified, and they will be applied left-to-right
759791simultaneously, so only one pattern will be applied to any character, and the
760792patterns will only be applied to the input text, not the replacements.
761793
762794!!! compat "Julia 1.7"
763795 Support for multiple patterns requires version 1.7.
764796
797+ !!! compat "Julia 1.10"
798+ The `out::IO` argument requires version 1.10.
799+
765800# Examples
766801```jldoctest
767802julia> replace("Python is a programming language.", "Python" => "Julia")
@@ -780,8 +815,18 @@ julia> replace("abcabc", "a" => "b", "b" => "c", r".+" => "a")
780815"bca"
781816```
782817"""
818+ replace (out:: IO , s:: AbstractString , pat_f:: Pair... ; count= typemax (Int)) =
819+ _replace_io (out, String (s), pat_f... , count= count)
820+
783821replace (s:: AbstractString , pat_f:: Pair... ; count= typemax (Int)) =
784- replace (String (s), pat_f... , count= count)
822+ _replace_str (String (s), pat_f... , count= count)
823+
824+ # no copy needed for SubString{String}
825+ replace (out:: IO , s:: SubString{String} , pat_f:: Pair... ; count= typemax (Int)) =
826+ _replace_io (out, s, pat_f... , count= count)
827+ replace (s:: SubString{String} , pat_f:: Pair... ; count= typemax (Int)) =
828+ _replace_str (s, pat_f... , count= count)
829+
785830
786831# TODO : allow transform as the first argument to replace?
787832
0 commit comments