@@ -700,12 +700,11 @@ _free_pat_replacer(x) = nothing
700
700
_pat_replacer (x:: AbstractChar ) = isequal (x)
701
701
_pat_replacer (x:: Union{Tuple{Vararg{AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}} ) = in (x)
702
702
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
705
705
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)
709
708
patterns = map (p -> _pat_replacer (first (p)), pat_repl)
710
709
replaces = map (last, pat_repl)
711
710
rs = map (patterns) do p
@@ -716,21 +715,24 @@ function replace(str::String, pat_repl::Vararg{Pair,N}; count::Integer=typemax(I
716
715
r isa Int && (r = r: r) # findnext / performance fix
717
716
return r
718
717
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)
724
726
while true
725
727
p = argmin (map (first, rs)) # TODO : or argmin(rs), to pick the shortest first match ?
726
728
r = rs[p]
727
729
j, k = first (r), last (r)
728
730
j > e1 && break
729
731
if i == a || i <= k
730
732
# 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))
732
734
# copy out replacement string
733
- _replace (out , replaces[p], str, r, patterns[p])
735
+ _replace (io , replaces[p], str, r, patterns[p])
734
736
end
735
737
if k < j
736
738
i = j
@@ -755,13 +757,39 @@ function replace(str::String, pat_repl::Vararg{Pair,N}; count::Integer=typemax(I
755
757
n += 1
756
758
end
757
759
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)
760
777
end
761
778
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
762
790
763
791
"""
764
- replace(s::AbstractString, pat=>r, [pat2=>r2, ...]; [count::Integer])
792
+ replace([io::IO], s::AbstractString, pat=>r, [pat2=>r2, ...]; [count::Integer])
765
793
766
794
Search for the given pattern `pat` in `s`, and replace each occurrence with `r`.
767
795
If `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
774
802
references in `r` are replaced with the corresponding matched text.
775
803
To remove instances of `pat` from `string`, set `r` to the empty `String` (`""`).
776
804
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
+
777
810
Multiple patterns can be specified, and they will be applied left-to-right
778
811
simultaneously, so only one pattern will be applied to any character, and the
779
812
patterns will only be applied to the input text, not the replacements.
780
813
781
814
!!! compat "Julia 1.7"
782
815
Support for multiple patterns requires version 1.7.
783
816
817
+ !!! compat "Julia 1.10"
818
+ The `io::IO` argument requires version 1.10.
819
+
784
820
# Examples
785
821
```jldoctest
786
822
julia> replace("Python is a programming language.", "Python" => "Julia")
@@ -799,8 +835,12 @@ julia> replace("abcabc", "a" => "b", "b" => "c", r".+" => "a")
799
835
"bca"
800
836
```
801
837
"""
838
+ replace (io:: IO , s:: AbstractString , pat_f:: Pair... ; count= typemax (Int)) =
839
+ _replace_ (io, String (s), pat_f, Int (count))
840
+
802
841
replace (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
+
804
844
805
845
# TODO : allow transform as the first argument to replace?
806
846
0 commit comments