Skip to content

Commit 9389f74

Browse files
authored
lower-level replace(...) hooks in latest Julia (#21)
* lower-level replace(...) hooks in latest Julia * multiple replacements require julia 1.7
1 parent c311bc1 commit 9389f74

File tree

2 files changed

+64
-39
lines changed

2 files changed

+64
-39
lines changed

src/util.jl

+54-39
Original file line numberDiff line numberDiff line change
@@ -36,49 +36,64 @@ function Base.chomp(s::StringViewAndSub)
3636
end
3737
end
3838

39-
Base.replace(str::DenseStringViewAndSub, pat_repl::Pair{<:AbstractChar}; count::Integer=typemax(Int)) =
40-
replace(str, isequal(first(pat_repl)) => last(pat_repl); count=count)
4139

42-
Base.replace(str::DenseStringViewAndSub, pat_repl::Pair{<:Union{Tuple{Vararg{AbstractChar}},
43-
AbstractVector{<:AbstractChar},Set{<:AbstractChar}}};
44-
count::Integer=typemax(Int)) =
45-
replace(str, in(first(pat_repl)) => last(pat_repl), count=count)
40+
# support replace via JuliaLang/julia#48625
41+
if isdefined(Base, :_replace_)
42+
Base.replace(io::IO, s::DenseStringViewAndSub, pat_f::Pair...; count=typemax(Int)) =
43+
Base._replace_(io, s, pat_f, Int(count))
4644

47-
import Base: _pat_replacer, _free_pat_replacer
48-
49-
function Base.replace(str::DenseStringViewAndSub, pat_repl::Pair; count::Integer=typemax(Int))
50-
pattern, repl = pat_repl
51-
count == 0 && return str
52-
count < 0 && throw(DomainError(count, "`count` must be non-negative."))
53-
n = 1
54-
e = lastindex(str)
55-
i = a = firstindex(str)
56-
pattern = _pat_replacer(pattern)
57-
r = something(findnext(pattern,str,i), 0)
58-
j, k = first(r), last(r)
59-
if j == 0
60-
_free_pat_replacer(pattern)
61-
return str
45+
function Base.replace(s::DenseStringViewAndSub, pat_f::Pair...; count=typemax(Int))
46+
# don't simply call Base._replace_(s, pat_f, Int(count)),
47+
# to avoid type-instability for empty-replacements case: always return String
48+
# (remove when #50424 is merged)
49+
buf = IOBuffer(sizehint=floor(Int, 1.2sizeof(s)))
50+
return String(take!(replace(buf, s, pat_f...; count=count)))
6251
end
63-
out = IOBuffer(sizehint=floor(Int, 1.2sizeof(str)))
64-
while j != 0
65-
if i == a || i <= k
66-
GC.@preserve str unsafe_write(out, pointer(str, i), UInt(j-i))
67-
Base._replace(out, repl, str, r, pattern)
52+
else
53+
Base.replace(str::DenseStringViewAndSub, pat_repl::Pair{<:AbstractChar}; count::Integer=typemax(Int)) =
54+
replace(str, isequal(first(pat_repl)) => last(pat_repl); count=count)
55+
56+
Base.replace(str::DenseStringViewAndSub, pat_repl::Pair{<:Union{Tuple{Vararg{AbstractChar}},
57+
AbstractVector{<:AbstractChar},Set{<:AbstractChar}}};
58+
count::Integer=typemax(Int)) =
59+
replace(str, in(first(pat_repl)) => last(pat_repl), count=count)
60+
61+
import Base: _pat_replacer, _free_pat_replacer
62+
63+
function Base.replace(str::DenseStringViewAndSub, pat_repl::Pair; count::Integer=typemax(Int))
64+
pattern, repl = pat_repl
65+
count == 0 && return str
66+
count < 0 && throw(DomainError(count, "`count` must be non-negative."))
67+
n = 1
68+
e = lastindex(str)
69+
i = a = firstindex(str)
70+
pattern = _pat_replacer(pattern)
71+
r = something(findnext(pattern,str,i), 0)
72+
j, k = first(r), last(r)
73+
if j == 0
74+
_free_pat_replacer(pattern)
75+
return str
6876
end
69-
if k < j
70-
i = j
71-
j > e && break
72-
k = nextind(str, j)
73-
else
74-
i = k = nextind(str, k)
77+
out = IOBuffer(sizehint=floor(Int, 1.2sizeof(str)))
78+
while j != 0
79+
if i == a || i <= k
80+
GC.@preserve str unsafe_write(out, pointer(str, i), UInt(j-i))
81+
Base._replace(out, repl, str, r, pattern)
82+
end
83+
if k < j
84+
i = j
85+
j > e && break
86+
k = nextind(str, j)
87+
else
88+
i = k = nextind(str, k)
89+
end
90+
r = something(findnext(pattern,str,k), 0)
91+
r === 0:-1 || n == count && break
92+
j, k = first(r), last(r)
93+
n += 1
7594
end
76-
r = something(findnext(pattern,str,k), 0)
77-
r === 0:-1 || n == count && break
78-
j, k = first(r), last(r)
79-
n += 1
95+
_free_pat_replacer(pattern)
96+
write(out, SubString(str,i))
97+
String(take!(out))
8098
end
81-
_free_pat_replacer(pattern)
82-
write(out, SubString(str,i))
83-
String(take!(out))
8499
end

test/runtests.jl

+10
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,16 @@ end
140140
end
141141
end
142142

143+
@testset "replace" begin
144+
@test replace(StringView(b"abcd"), r"[bc]?" => "^") == "^a^^d^"
145+
@test replace(StringView(b"a"), 'a' => typeof) == "Char"
146+
@test replace(StringView(b"The foxes."), r"fox(es)?" => s"bus\1") == "The buses."
147+
if VERSION v"1.7" # for multiple replacements
148+
@test replace(StringView(b"foobarbaz"), "oo" => "zz", "ar" => "zz", "z" => "m") == "fzzbzzbam"
149+
@test replace(StringView(b"foobar"), 'o' => '0', "" => "") == "f00bar"
150+
end
151+
end
152+
143153
@testset "miscellaneous" begin
144154
@test cmp("foobar","bar") == cmp(s,"bar") == -cmp("bar",s) == cmp(s,StringView("bar"))
145155
@test s == StringView("foobar") == "foobar" == s == "foobar" != StringView("bar")

0 commit comments

Comments
 (0)