diff --git a/NEWS.md b/NEWS.md
index 77a3150a36e39..850f483301714 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -115,6 +115,9 @@ Language changes
* The keyword `importall` is deprecated. Use `using` and/or individual `import` statements
instead ([#22789]).
+ * The `RevString` type for lazily reversed strings has been moved to the LegacyStrings
+ package ([#22611]).
+
Breaking changes
----------------
@@ -243,6 +246,9 @@ This section lists changes that do not have deprecation warnings.
* All command line arguments passed via `-e`, `-E`, and `-L` will be executed in the order
given on the command line ([#23665]).
+ * `reverse(::AbstractString)` now unconditionally returns a `String`. Previously it
+ returned a `RepString`, which has been removed from Base ([#23612]).
+
Library improvements
--------------------
@@ -1358,6 +1364,7 @@ Command-line option changes
[#22532]: https://github.com/JuliaLang/julia/issues/22532
[#22588]: https://github.com/JuliaLang/julia/issues/22588
[#22605]: https://github.com/JuliaLang/julia/issues/22605
+[#22611]: https://github.com/JuliaLang/julia/issues/22611
[#22666]: https://github.com/JuliaLang/julia/issues/22666
[#22696]: https://github.com/JuliaLang/julia/issues/22696
[#22703]: https://github.com/JuliaLang/julia/issues/22703
@@ -1387,3 +1394,4 @@ Command-line option changes
[#23233]: https://github.com/JuliaLang/julia/issues/23233
[#23342]: https://github.com/JuliaLang/julia/issues/23342
[#23404]: https://github.com/JuliaLang/julia/issues/23404
+[#23612]: https://github.com/JuliaLang/julia/issues/23612
diff --git a/base/deprecated.jl b/base/deprecated.jl
index 9b70231113c31..c17d101976499 100644
--- a/base/deprecated.jl
+++ b/base/deprecated.jl
@@ -1855,6 +1855,9 @@ end
# also remove deprecation warnings in find* functions in array.jl, sparse/sparsematrix.jl,
# and sparse/sparsevector.jl.
+# Issue #22611
+@deprecate_moved RevString "LegacyStrings"
+
# END 0.7 deprecations
# BEGIN 1.0 deprecations
diff --git a/base/exports.jl b/base/exports.jl
index 09fd49d701fb2..6957dc3baf155 100644
--- a/base/exports.jl
+++ b/base/exports.jl
@@ -90,7 +90,6 @@ export
Rational,
Regex,
RegexMatch,
- RevString,
RoundFromZero,
RoundDown,
RoundingMode,
diff --git a/base/precompile.jl b/base/precompile.jl
index 86bcc216f32c8..cc1a1325fd1b2 100644
--- a/base/precompile.jl
+++ b/base/precompile.jl
@@ -581,9 +581,6 @@ precompile(Tuple{typeof(Base.LineEdit.complete_line), Base.LineEdit.PromptState,
precompile(Tuple{typeof(Base.LineEdit.input_string_newlines_aftercursor), Base.LineEdit.PromptState})
precompile(Tuple{typeof(Base.LineEdit.complete_line), Base.REPL.REPLCompletionProvider, Base.LineEdit.PromptState})
precompile(Tuple{getfield(Base, Symbol("#kw##parse")), Array{Any, 1}, typeof(Base.parse), String})
-precompile(Tuple{typeof(Base.isvalid), Base.RevString{String}, Int64})
-precompile(Tuple{typeof(Base.nextind), Base.RevString{String}, Int64})
-precompile(Tuple{typeof(Base.search), Base.RevString{String}, Array{Char, 1}, Int64})
precompile(Tuple{typeof(Base.rsearch), String, Array{Char, 1}, Int64})
precompile(Tuple{getfield(Base.REPLCompletions, Symbol("#kw##find_start_brace")), Array{Any, 1}, typeof(Base.REPLCompletions.find_start_brace), String})
precompile(Tuple{typeof(Core.Inference.isbits), Tuple{Void, Void, Void}})
diff --git a/base/repl/REPLCompletions.jl b/base/repl/REPLCompletions.jl
index 1e380b7150149..680431fdbfff7 100644
--- a/base/repl/REPLCompletions.jl
+++ b/base/repl/REPLCompletions.jl
@@ -225,13 +225,13 @@ end
# closed start brace from the end of the string.
function find_start_brace(s::AbstractString; c_start='(', c_end=')')
braces = 0
- r = RevString(s)
- i = start(r)
+ i = endof(s)
in_single_quotes = false
in_double_quotes = false
in_back_ticks = false
- while !done(r, i)
- c, i = next(r, i)
+ while i > 0
+ c = s[i]
+ nexti = prevind(s, i)
if !in_single_quotes && !in_double_quotes && !in_back_ticks
if c == c_start
braces += 1
@@ -245,18 +245,19 @@ function find_start_brace(s::AbstractString; c_start='(', c_end=')')
in_back_ticks = true
end
else
- if !in_back_ticks && !in_double_quotes && c == '\'' && !done(r, i) && next(r, i)[1]!='\\'
+ if !in_back_ticks && !in_double_quotes && c == '\'' && i > 0 && s[nexti] != '\\'
in_single_quotes = !in_single_quotes
- elseif !in_back_ticks && !in_single_quotes && c == '"' && !done(r, i) && next(r, i)[1]!='\\'
+ elseif !in_back_ticks && !in_single_quotes && c == '"' && i > 0 && s[nexti] != '\\'
in_double_quotes = !in_double_quotes
- elseif !in_single_quotes && !in_double_quotes && c == '`' && !done(r, i) && next(r, i)[1]!='\\'
+ elseif !in_single_quotes && !in_double_quotes && c == '`' && i > 0 && s[nexti] != '\\'
in_back_ticks = !in_back_ticks
end
end
braces == 1 && break
+ i = nexti
end
braces != 1 && return 0:-1, -1
- method_name_end = reverseind(r, i)
+ method_name_end = i - 1
startind = nextind(s, rsearch(s, non_identifier_chars, method_name_end))
return (startind:endof(s), method_name_end)
end
diff --git a/base/shell.jl b/base/shell.jl
index 841865790b9c9..680cd45c722ad 100644
--- a/base/shell.jl
+++ b/base/shell.jl
@@ -12,21 +12,20 @@ function shell_parse(str::AbstractString, interpolate::Bool=true;
special::AbstractString="")
s = lstrip(str)
# strips the end but respects the space when the string ends with "\\ "
- r = RevString(s)
- i = start(r)
- c_old = nothing
- while !done(r,i)
- c, j = next(r,i)
+ i = endof(s)
+ c_old = '\0' # initialized to a null byte for type stability
+ while i > 0
+ c = s[i]
if c == '\\' && c_old == ' '
- i -= 1
+ i += 1
break
elseif !(c in _default_delims)
break
end
- i = j
+ i = prevind(s, i)
c_old = c
end
- s = s[1:end-i+1]
+ s = s[1:i]
last_parse = 0:-1
isempty(s) && return interpolate ? (Expr(:tuple,:()),last_parse) : ([],last_parse)
diff --git a/base/strings/basic.jl b/base/strings/basic.jl
index b214fba344ecd..3dde366eef821 100644
--- a/base/strings/basic.jl
+++ b/base/strings/basic.jl
@@ -611,3 +611,77 @@ function filter(f, s::AbstractString)
end
String(take!(out))
end
+
+"""
+ reverse(s::AbstractString) -> String
+
+Reverse a string. The result is always a `String`, regardless of the input type.
+
+Technically, this function reverses the codepoints in a string, and its
+main utility is for reversed-order string processing, especially for reversed
+regular-expression searches. See also [`reverseind`](@ref) to convert indices
+in `s` to indices in `reverse(s)` and vice-versa, and [`graphemes`](@ref)
+to operate on user-visible "characters" (graphemes) rather than codepoints.
+
+# Examples
+```jldoctest
+julia> reverse("JuliaLang")
+"gnaLailuJ"
+
+julia> reverse("ax̂e") # combining characters can lead to surprising results
+"êxa"
+
+julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes
+"ex̂a"
+```
+"""
+reverse(s::AbstractString) = reverse(convert(String, s))
+
+## reverse an index i so that reverse(s)[i] == s[reverseind(s,i)]
+
+"""
+ reverseind(v, i)
+
+Given an index `i` in [`reverse(v)`](@ref), return the corresponding index in `v` so that
+`v[reverseind(v,i)] == reverse(v)[i]`. (This can be nontrivial in cases where `v` contains
+non-ASCII characters.)
+
+# Examples
+```jldoctest
+julia> r = reverse("Julia")
+"ailuJ"
+
+julia> for i in 1:length(r)
+ print(r[reverseind("Julia", i)])
+ end
+Julia
+```
+"""
+reverseind(s::AbstractString, i) = chr2ind(s, length(s) + 1 - ind2chr(reverse(s), i))
+
+"""
+ repeat(s::AbstractString, r::Integer)
+
+Repeat a string `r` times. This can equivalently be accomplished by calling [`s^r`](@ref ^).
+
+# Examples
+```jldoctest
+julia> repeat("ha", 3)
+"hahaha"
+```
+"""
+repeat(s::AbstractString, r::Integer) = repeat(convert(String, s), r)
+
+"""
+ ^(s::Union{AbstractString,Char}, n::Integer)
+
+Repeat a string or character `n` times.
+The [`repeat`](@ref) function is an alias to this operator.
+
+# Examples
+```jldoctest
+julia> "Test "^3
+"Test Test Test "
+```
+"""
+(^)(s::Union{AbstractString,Char}, r::Integer) = repeat(s, r)
diff --git a/base/strings/search.jl b/base/strings/search.jl
index 23f813ea28b26..09bf37217e157 100644
--- a/base/strings/search.jl
+++ b/base/strings/search.jl
@@ -194,12 +194,6 @@ end
search(s::AbstractString, t::AbstractString, i::Integer=start(s)) = _search(s, t, i)
search(s::ByteArray, t::ByteArray, i::Integer=start(s)) = _search(s, t, i)
-function rsearch(s::AbstractString, c::Chars)
- j = search(RevString(s), c)
- j == 0 && return 0
- endof(s)-j+1
-end
-
"""
rsearch(s::AbstractString, chars::Chars, [start::Integer])
@@ -212,44 +206,48 @@ julia> rsearch("aaabbb","b")
6:6
```
"""
-function rsearch(s::AbstractString, c::Chars, i::Integer)
- e = endof(s)
- j = search(RevString(s), c, e-i+1)
- j == 0 && return 0
- e-j+1
+function rsearch(s::AbstractString, c::Chars, i::Integer=endof(s))
+ @boundscheck checkbounds(s, i)
+ isempty(c) && return i
+ j = Int(i)
+ @inbounds while j > 0
+ s[j] in c && return j
+ j = prevind(s, j)
+ end
+ return 0
end
function _rsearchindex(s, t, i)
if isempty(t)
- return 1 <= i <= nextind(s,endof(s)) ? i :
- throw(BoundsError(s, i))
+ @boundscheck checkbounds(s, i)
+ return i
end
- t = RevString(t)
- rs = RevString(s)
l = endof(s)
- t1, j2 = next(t,start(t))
+ j2 = endof(t)
+ t1 = t[j2]
while true
- i = rsearch(s,t1,i)
- if i == 0 return 0 end
- c, ii = next(rs,l-i+1)
- j = j2; k = ii
+ i = rsearch(s, t1, i)
+ i == 0 && return 0
+ c = s[i]
+ ii = prevind(s, i)
+ j, k = j2, ii
matched = true
- while !done(t,j)
- if done(rs,k)
+ while j > 1
+ if k < 1
matched = false
break
end
- c, k = next(rs,k)
- d, j = next(t,j)
+ k = prevind(s, k)
+ c = s[k]
+ j = prevind(t, j)
+ d = t[j]
if c != d
matched = false
break
end
end
- if matched
- return nextind(s,l-k+1)
- end
- i = l-ii+1
+ matched && return nextind(s, k)
+ i = ii
end
end
diff --git a/base/strings/types.jl b/base/strings/types.jl
index 9e74a83a39d6a..64761672dd90a 100644
--- a/base/strings/types.jl
+++ b/base/strings/types.jl
@@ -1,6 +1,6 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license
-# SubString and RevString types
+# SubString type
## substrings reference original strings ##
@@ -98,47 +98,6 @@ function unsafe_convert(::Type{Ptr{R}}, s::SubString{String}) where R<:Union{Int
convert(Ptr{R}, pointer(s.string)) + s.offset
end
-## reversed strings without data movement ##
-
-struct RevString{T<:AbstractString} <: AbstractString
- string::T
-end
-
-endof(s::RevString) = endof(s.string)
-length(s::RevString) = length(s.string)
-sizeof(s::RevString) = sizeof(s.string)
-
-function next(s::RevString, i::Int)
- n = endof(s); j = n-i+1
- (s.string[j], n-prevind(s.string,j)+1)
-end
-
-"""
- reverse(s::AbstractString) -> AbstractString
-
-Reverses a string.
-
-Technically, this function reverses the codepoints in a string, and its
-main utility is for reversed-order string processing, especially for reversed
-regular-expression searches. See also [`reverseind`](@ref) to convert indices
-in `s` to indices in `reverse(s)` and vice-versa, and [`graphemes`](@ref)
-to operate on user-visible "characters" (graphemes) rather than codepoints.
-
-# Examples
-```jldoctest
-julia> reverse("JuliaLang")
-"gnaLailuJ"
-
-julia> reverse("ax̂e") # combining characters can lead to surprising results
-"êxa"
-
-julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes
-"ex̂a"
-```
-"""
-reverse(s::AbstractString) = RevString(s)
-reverse(s::RevString) = s.string
-
## reverse an index i so that reverse(s)[i] == s[reverseind(s,i)]
"""
@@ -161,7 +120,6 @@ Julia
"""
reverseind(s::AbstractString, i) = chr2ind(s, length(s) + 1 - ind2chr(reverse(s), i))
reverseind(s::Union{DirectIndexString,SubString{DirectIndexString}}, i::Integer) = length(s) + 1 - i
-reverseind(s::RevString, i::Integer) = endof(s) - i + 1
reverseind(s::SubString{String}, i::Integer) =
reverseind(s.string, nextind(s.string, endof(s.string))-s.offset-s.endof+i-1) - s.offset
diff --git a/base/strings/util.jl b/base/strings/util.jl
index fd9a055f06352..f8e238e2f8e2c 100644
--- a/base/strings/util.jl
+++ b/base/strings/util.jl
@@ -173,14 +173,10 @@ julia> rstrip(a)
```
"""
function rstrip(s::AbstractString, chars::Chars=_default_delims)
- r = RevString(s)
- i = start(r)
- while !done(r,i)
- c, j = next(r,i)
- if !(c in chars)
- return SubString(s, 1, endof(s)-i+1)
- end
- i = j
+ i = endof(s)
+ while i > 0
+ s[i] in chars || return SubString(s, 1, i)
+ i = prevind(s, i)
end
SubString(s, 1, 0)
end
diff --git a/contrib/Julia_Notepad++.xml b/contrib/Julia_Notepad++.xml
index e43a1ab4865ee..306706ffc3c8e 100644
--- a/contrib/Julia_Notepad++.xml
+++ b/contrib/Julia_Notepad++.xml
@@ -25,7 +25,7 @@
true false C_NULL Inf NaN Inf32 NaN32 nothing
- AbstractArray AbstractMatrix AbstractRange AbstractRemoteRef AbstractSparseMatrix AbstractString AbstractVector Any ArgumentError Array Associative BigFloat BigInt BitArray BitMatrix BitVector Bool BunchKaufman Cchar Cdouble Cfloat Char CharString CholeskyDense CholeskyPivotedDense Cint Cintmax_t Clong Clonglong Colon Complex Complex128 Complex64 ComplexPair Cptrdiff_t Cshort Csize_t Cuchar Cuint Cuintmax_t Culong Culonglong Cushort DArray Dict Dims DisconnectException EOFError EachLine EnvHash ErrorException Exception Expr Factorization Filter Float Float32 Float64 Function GSVDDense IO IOBuffer IOStream ImaginaryUnit InsertionSort Int Int128 Int16 Int32 Int64 Int8 IntSet Integer KeyError LDLTTridiagonal LUDense LUTridiagonal LoadError LocalProcess Matrix MergeSort MethodError NTuple Number ObjectIdDict ObjectIdDict OrdinalRange ParseError PipeBuffer ProcessGroup Ptr QRDense QRPivotedDense QuickSort RangeIndex Rational Real Regex RegexMatch RegexMatchIterator RepString RevString Reverse SVDDense Set Signed SparseMatrixCSC SpawnNullStream Stat StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubDArray SubOrDArray SubString SymTridiagonal Symbol SystemError Task TCPSocket TimSort Tridiagonal Tuple Type TypeError UInt UInt128 UInt16 UInt32 UInt64 UInt8 UVError Union UnitRange Unsigned VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef Zip
+ AbstractArray AbstractMatrix AbstractRange AbstractRemoteRef AbstractSparseMatrix AbstractString AbstractVector Any ArgumentError Array Associative BigFloat BigInt BitArray BitMatrix BitVector Bool BunchKaufman Cchar Cdouble Cfloat Char CharString CholeskyDense CholeskyPivotedDense Cint Cintmax_t Clong Clonglong Colon Complex Complex128 Complex64 ComplexPair Cptrdiff_t Cshort Csize_t Cuchar Cuint Cuintmax_t Culong Culonglong Cushort DArray Dict Dims DisconnectException EOFError EachLine EnvHash ErrorException Exception Expr Factorization Filter Float Float32 Float64 Function GSVDDense IO IOBuffer IOStream ImaginaryUnit InsertionSort Int Int128 Int16 Int32 Int64 Int8 IntSet Integer KeyError LDLTTridiagonal LUDense LUTridiagonal LoadError LocalProcess Matrix MergeSort MethodError NTuple Number ObjectIdDict ObjectIdDict OrdinalRange ParseError PipeBuffer ProcessGroup Ptr QRDense QRPivotedDense QuickSort RangeIndex Rational Real Regex RegexMatch RegexMatchIterator RepString Reverse SVDDense Set Signed SparseMatrixCSC SpawnNullStream Stat StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubDArray SubOrDArray SubString SymTridiagonal Symbol SystemError Task TCPSocket TimSort Tridiagonal Tuple Type TypeError UInt UInt128 UInt16 UInt32 UInt64 UInt8 UVError Union UnitRange Unsigned VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef Zip
abstract begin baremodule primitive break catch ccall const continue do else elseif end export finally for function global if struct import importall let local macro module quote return try mutable typealias using while
close enumerate error info open print println read write warn
print println
diff --git a/contrib/julia.xml b/contrib/julia.xml
index a0bb9c33b7984..46b35c0f307ff 100644
--- a/contrib/julia.xml
+++ b/contrib/julia.xml
@@ -156,7 +156,6 @@
- RegexMatch
- RegexMatchIterator
- RepString
- - RevString
- Reverse
- Schur
- Set
diff --git a/doc/src/manual/interacting-with-julia.md b/doc/src/manual/interacting-with-julia.md
index 40b68bf8221b3..365c24fa02650 100644
--- a/doc/src/manual/interacting-with-julia.md
+++ b/doc/src/manual/interacting-with-julia.md
@@ -67,7 +67,7 @@ When the cursor is at the beginning of the line, the prompt can be changed to a
julia> ? # upon typing ?, the prompt changes (in place) to: help?>
help?> string
-search: string String stringmime Cstring Cwstring RevString randstring bytestring SubString
+search: string String stringmime Cstring Cwstring randstring bytestring SubString
string(xs...)
diff --git a/test/strings/types.jl b/test/strings/types.jl
index 6efab9d92a18d..4714d2b4e9693 100644
--- a/test/strings/types.jl
+++ b/test/strings/types.jl
@@ -1,6 +1,6 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license
-## SubString, RevString and Cstring tests ##
+## SubString and Cstring tests ##
## SubString tests ##
u8str = "∀ ε > 0, ∃ δ > 0: |x-y| < δ ⇒ |f(x)-f(y)| < ε"
@@ -163,36 +163,24 @@ end
## Reverse strings ##
-let rs = RevString("foobar")
- @test length(rs) == 6
- @test sizeof(rs) == 6
- @test isascii(rs)
-end
-
-# issue #4586
-@test rsplit(RevString("ailuj"),'l') == ["ju","ia"]
-@test parse(Float64,RevString("64")) === 46.0
-
# reverseind
for T in (String, GenericString)
for prefix in ("", "abcd", "\U0001d6a4\U0001d4c1", "\U0001d6a4\U0001d4c1c", " \U0001d6a4\U0001d4c1")
for suffix in ("", "abcde", "\U0001d4c1β\U0001d6a4", "\U0001d4c1β\U0001d6a4c", " \U0001d4c1β\U0001d6a4")
for c in ('X', 'δ', '\U0001d6a5')
- s = convert(T, string(prefix, c, suffix))
- r = reverse(s)
- ri = search(r, c)
- @test r == RevString(s)
- @test c == s[reverseind(s, ri)] == r[ri]
- s = RevString(s)
- r = reverse(s)
- ri = search(r, c)
- @test c == s[reverseind(s, ri)] == r[ri]
- s = convert(T, string(prefix, prefix, c, suffix, suffix))
- pre = convert(T, prefix)
- sb = SubString(s, nextind(pre, endof(pre)), endof(convert(T, string(prefix, prefix, c, suffix))))
- r = reverse(sb)
- ri = search(r, c)
- @test c == sb[reverseind(sb, ri)] == r[ri]
+ let s = convert(T, string(prefix, c, suffix))
+ r = reverse(String(s))
+ ri = search(r, c)
+ @test c == s[reverseind(s, ri)] == r[ri]
+ end
+ let s = convert(T, string(prefix, prefix, c, suffix, suffix))
+ pre = convert(T, prefix)
+ sb = SubString(s, nextind(pre, endof(pre)), endof(convert(T, string(prefix, prefix, c, suffix))))
+ r = reverse(String(sb))
+ ri = search(r, c)
+ sbs = String(sb)
+ @test c == sbs[reverseind(sbs, ri)] == r[ri]
+ end
end
end
end