diff --git a/NEWS.md b/NEWS.md index c5428bcce5629..db83648157df9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -900,6 +900,14 @@ Deprecated or removed in favor of dot overloading (`getproperty`) so factors should now be accessed as e.g. `F.Q` instead of `F[:Q]` ([#25184]). + * `search` and `rsearch` have been deprecated in favor of `findfirst`/`findnext` and + `findlast`/`findprev` respectively, in combination with the new `equalto` and `occursin` + predicates for some methods ([#24673] + + * `ismatch(regex, str)` has been deprecated in favor of `contains(str, regex)` ([#24673]). + + * `findin(a, b)` has been deprecated in favor of `find(occursin(b), a)` ([#24673]). + Command-line option changes --------------------------- diff --git a/base/abstractarray.jl b/base/abstractarray.jl index a763308716d8a..b119b1d2e356a 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1055,7 +1055,7 @@ get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T # 1d is not linear indexing - ind = findin(I, indices1(A)) + ind = find(occursin(indices1(A)), I) X[ind] = A[I[ind]] Xind = indices1(X) X[first(Xind):first(ind)-1] = default @@ -1064,7 +1064,7 @@ function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,Ab end function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T # Linear indexing - ind = findin(I, 1:length(A)) + ind = find(occursin(1:length(A)), I) X[ind] = A[I[ind]] X[1:first(ind)-1] = default X[last(ind)+1:length(X)] = default @@ -1237,7 +1237,7 @@ _cs(d, a, b) = (a == b ? a : throw(DimensionMismatch( "mismatch in dimension $d (expected $a got $b)"))) dims2cat(::Val{n}) where {n} = ntuple(i -> (i == n), Val(n)) -dims2cat(dims) = ntuple(i -> (i in dims), maximum(dims)) +dims2cat(dims) = ntuple(occursin(dims), maximum(dims)) cat(dims, X...) = cat_t(dims, promote_eltypeof(X...), X...) diff --git a/base/array.jl b/base/array.jl index 045b2297fa926..de3748e0319f7 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1799,6 +1799,7 @@ end find(x::Bool) = x ? [1] : Vector{Int}() find(testf::Function, x::Number) = !testf(x) ? Vector{Int}() : [1] +find(p::OccursIn, x::Number) = x in p.x ? Vector{Int}() : [1] """ findnz(A) @@ -2008,7 +2009,7 @@ function _findin(a, b) ind end -# If two collections are already sorted, findin can be computed with +# If two collections are already sorted, _findin can be computed with # a single traversal of the two collections. This is much faster than # using a hash table (although it has the same complexity). function _sortedfindin(v, w) @@ -2050,42 +2051,16 @@ function _sortedfindin(v, w) return out end -""" - findin(a, b) - -Return the indices of elements in collection `a` that appear in collection `b`. - -# Examples -```jldoctest -julia> a = collect(1:3:15) -5-element Array{Int64,1}: - 1 - 4 - 7 - 10 - 13 - -julia> b = collect(2:4:10) -3-element Array{Int64,1}: - 2 - 6 - 10 - -julia> findin(a,b) # 10 is the only common element -1-element Array{Int64,1}: - 4 -``` -""" -function findin(a::Array{<:Real}, b::Union{Array{<:Real},Real}) - if issorted(a, Sort.Forward) && issorted(b, Sort.Forward) - return _sortedfindin(a, b) +function find(pred::OccursIn{<:Union{Array{<:Real},Real}}, x::Array{<:Real}) + if issorted(x, Sort.Forward) && issorted(pred.x, Sort.Forward) + return _sortedfindin(x, pred.x) else - return _findin(a, b) + return _findin(x, pred.x) end end # issorted fails for some element types so the method above has to be restricted # to element with isless/< defined. -findin(a, b) = _findin(a, b) +find(pred::OccursIn, x::Union{AbstractArray, Tuple}) = _findin(x, pred.x) # Copying subregions function indcopy(sz::Dims, I::Vector) @@ -2094,8 +2069,8 @@ function indcopy(sz::Dims, I::Vector) for i = n+1:length(sz) s *= sz[i] end - dst = eltype(I)[findin(I[i], i < n ? (1:sz[i]) : (1:s)) for i = 1:n] - src = eltype(I)[I[i][findin(I[i], i < n ? (1:sz[i]) : (1:s))] for i = 1:n] + dst = eltype(I)[_findin(I[i], i < n ? (1:sz[i]) : (1:s)) for i = 1:n] + src = eltype(I)[I[i][_findin(I[i], i < n ? (1:sz[i]) : (1:s))] for i = 1:n] dst, src end @@ -2105,8 +2080,8 @@ function indcopy(sz::Dims, I::Tuple{Vararg{RangeIndex}}) for i = n+1:length(sz) s *= sz[i] end - dst::typeof(I) = ntuple(i-> findin(I[i], i < n ? (1:sz[i]) : (1:s)), n)::typeof(I) - src::typeof(I) = ntuple(i-> I[i][findin(I[i], i < n ? (1:sz[i]) : (1:s))], n)::typeof(I) + dst::typeof(I) = ntuple(i-> _findin(I[i], i < n ? (1:sz[i]) : (1:s)), n)::typeof(I) + src::typeof(I) = ntuple(i-> I[i][_findin(I[i], i < n ? (1:sz[i]) : (1:s))], n)::typeof(I) dst, src end diff --git a/base/deprecated.jl b/base/deprecated.jl index 5f8e8d7f2a141..75995dd1d585b 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -3813,7 +3813,6 @@ end @deprecate getq(F::Factorization) F.Q end -# issue #5290 @deprecate lexcmp(x::AbstractArray, y::AbstractArray) cmp(x, y) @deprecate lexcmp(x::Real, y::Real) cmp(isless, x, y) @deprecate lexcmp(x::Complex, y::Complex) cmp((real(x),imag(x)), (real(y),imag(y))) @@ -3821,8 +3820,58 @@ end @deprecate lexless isless -# END 0.7 deprecations +@deprecate search(str::Union{String,SubString}, re::Regex, idx::Integer) findnext(re, str, idx) +@deprecate search(s::AbstractString, r::Regex, idx::Integer) findnext(r, s, idx) +@deprecate search(s::AbstractString, r::Regex) findfirst(r, s) +@deprecate search(s::AbstractString, c::Char, i::Integer) findnext(equalto(c), s, i) +@deprecate search(s::AbstractString, c::Char) findfirst(equalto(c), s) +@deprecate search(a::ByteArray, b::Union{Int8,UInt8}, i::Integer) findnext(equalto(b), a, i) +@deprecate search(a::ByteArray, b::Union{Int8,UInt8}) findfirst(equalto(b), a) +@deprecate search(a::String, b::Union{Int8,UInt8}, i::Integer) findnext(equalto(b), unsafe_wrap(Vector{UInt8}, a), i) +@deprecate search(a::String, b::Union{Int8,UInt8}) findfirst(equalto(b), unsafe_wrap(Vector{UInt8}, a)) +@deprecate search(a::ByteArray, b::Char, i::Integer) findnext(equalto(UInt8(b)), a, i) +@deprecate search(a::ByteArray, b::Char) findfirst(equalto(UInt8(b)), a) + +@deprecate search(s::AbstractString, c::Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}, i::Integer) findnext(occursin(c), s, i) +@deprecate search(s::AbstractString, c::Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}) findfirst(occursin(c), s) +@deprecate search(s::AbstractString, t::AbstractString, i::Integer) findnext(t, s, i) +@deprecate search(s::AbstractString, t::AbstractString) findfirst(t, s) + +@deprecate search(buf::IOBuffer, delim::UInt8) findfirst(equalto(delim), buf) +@deprecate search(buf::Base.GenericIOBuffer, delim::UInt8) findfirst(equalto(delim), buf) + +@deprecate rsearch(s::AbstractString, c::Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}, i::Integer) findprev(occursin(c), s, i) +@deprecate rsearch(s::AbstractString, c::Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}) findlast(occursin(c), s) +@deprecate rsearch(s::AbstractString, t::AbstractString, i::Integer) findprev(t, s, i) +@deprecate rsearch(s::AbstractString, t::AbstractString) findlast(t, s) +@deprecate rsearch(s::ByteArray, t::ByteArray, i::Integer) findprev(t, s, i) +@deprecate rsearch(s::ByteArray, t::ByteArray) findlast(t, s) + +@deprecate rsearch(str::Union{String,SubString}, re::Regex, idx::Integer) findprev(re, str, idx) +@deprecate rsearch(str::Union{String,SubString}, re::Regex) findlast(re, str) +@deprecate rsearch(s::AbstractString, r::Regex, idx::Integer) findprev(r, s, idx) +@deprecate rsearch(s::AbstractString, r::Regex) findlast(r, s) +@deprecate rsearch(s::AbstractString, c::Char, i::Integer) findprev(equalto(c), s, i) +@deprecate rsearch(s::AbstractString, c::Char) findlast(equalto(c), s) +@deprecate rsearch(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = endof(a)) findprev(equalto(b), a, i) +@deprecate rsearch(a::String, b::Union{Int8,UInt8}, i::Integer = endof(a)) findprev(equalto(Char(b)), a, i) +@deprecate rsearch(a::ByteArray, b::Char, i::Integer = endof(a)) findprev(equalto(UInt8(b)), a, i) + +@deprecate searchindex(s::AbstractString, t::AbstractString) first(findfirst(t, s)) +@deprecate searchindex(s::AbstractString, t::AbstractString, i::Integer) first(findnext(t, s, i)) +@deprecate rsearchindex(s::AbstractString, t::AbstractString) first(findlast(t, s)) +@deprecate rsearchindex(s::AbstractString, t::AbstractString, i::Integer) first(findprev(t, s, i)) + +@deprecate searchindex(s::AbstractString, c::Char) first(findfirst(equalto(c), s)) +@deprecate searchindex(s::AbstractString, c::Char, i::Integer) first(findnext(equalto(c), s, i)) +@deprecate rsearchindex(s::AbstractString, c::Char) first(findlast(equalto(c), s)) +@deprecate rsearchindex(s::AbstractString, c::Char, i::Integer) first(findprev(equalto(c), s, i)) + +@deprecate ismatch(r::Regex, s::AbstractString) contains(s, r) + +@deprecate findin(a, b) find(occursin(b), a) +# END 0.7 deprecations # BEGIN 1.0 deprecations # END 1.0 deprecations diff --git a/base/docs/utils.jl b/base/docs/utils.jl index fe3151fa0486d..88d9db3c124d5 100644 --- a/base/docs/utils.jl +++ b/base/docs/utils.jl @@ -349,7 +349,7 @@ const builtins = ["abstract type", "baremodule", "begin", "break", moduleusings(mod) = ccall(:jl_module_usings, Any, (Any,), mod) -filtervalid(names) = filter(x->!ismatch(r"#", x), map(string, names)) +filtervalid(names) = filter(x->!contains(x, r"#"), map(string, names)) accessible(mod::Module) = [filter!(s -> !Base.isdeprecated(mod, s), names(mod, true, true)); @@ -363,7 +363,7 @@ completions(name::Symbol) = completions(string(name)) # Searching and apropos # Docsearch simply returns true or false if an object contains the given needle -docsearch(haystack::AbstractString, needle) = !isempty(search(haystack, needle)) +docsearch(haystack::AbstractString, needle) = !isempty(findfirst(needle, haystack)) docsearch(haystack::Symbol, needle) = docsearch(string(haystack), needle) docsearch(::Nothing, needle) = false function docsearch(haystack::Array, needle) diff --git a/base/exports.jl b/base/exports.jl index b566ccfaadb28..bbc505393a62e 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -409,18 +409,6 @@ export extrema, fill!, fill, - find, - findfirst, - findlast, - findin, - findmax, - findmin, - findmin!, - findmax!, - findn, - findnext, - findprev, - findnz, first, flipdim, hcat, @@ -476,9 +464,6 @@ export rot180, rotl90, rotr90, - searchsorted, - searchsortedfirst, - searchsortedlast, shuffle, shuffle!, size, @@ -501,6 +486,30 @@ export view, zeros, +# search, find, match and related functions + contains, + eachmatch, + endswith, + equalto, + find, + findfirst, + findlast, + findmax, + findmin, + findmin!, + findmax!, + findn, + findnext, + findprev, + findnz, + occursin, + match, + matchall, + searchsorted, + searchsortedfirst, + searchsortedlast, + startswith, + # linear algebra bkfact!, bkfact, @@ -611,7 +620,6 @@ export any!, any, collect, - contains, count, delete!, deleteat!, @@ -679,7 +687,6 @@ export # strings and text output ascii, base, - startswith, bin, bitstring, bytes2hex, @@ -691,22 +698,17 @@ export digits, digits!, dump, - eachmatch, - endswith, escape_string, hex, hex2bytes, hex2bytes!, info, isascii, - ismatch, isvalid, join, logging, lpad, lstrip, - match, - matchall, ncodeunits, ndigits, nextind, @@ -723,12 +725,8 @@ export repr, reverseind, rpad, - rsearch, - rsearchindex, rsplit, rstrip, - search, - searchindex, show, showcompact, showerror, @@ -800,7 +798,6 @@ export identity, isbits, isequal, - equalto, isimmutable, isless, ifelse, diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 57baed9af5b81..7627362cdca0f 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -334,13 +334,13 @@ function versioninfo(io::IO=STDOUT; verbose::Bool=false, packages::Bool=false) println(io, "Environment:") for (k,v) in ENV - if ismatch(r"JULIA", String(k)) + if contains(String(k), r"JULIA") println(io, " $(k) = $(v)") end end if verbose for (k,v) in ENV - if ismatch(r"PATH|FLAG|^TERM$|HOME", String(k)) + if contains(String(k), r"PATH|FLAG|^TERM$|HOME") println(io, " $(k) = $(v)") end end @@ -743,7 +743,7 @@ function varinfo(m::Module=Main, pattern::Regex=r"") (value ∈ (Base, Main, Core) ? "" : format_bytes(summarysize(value))), summary(value)] end - for v in sort!(names(m)) if isdefined(m, v) && ismatch(pattern, string(v)) ] + for v in sort!(names(m)) if isdefined(m, v) && contains(string(v), pattern) ] pushfirst!(rows, Any["name", "size", "summary"]) diff --git a/base/iobuffer.jl b/base/iobuffer.jl index b94b1f045e895..e91e8c30cd213 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -426,18 +426,18 @@ read(io::GenericIOBuffer) = read!(io,StringVector(nb_available(io))) readavailable(io::GenericIOBuffer) = read(io) read(io::GenericIOBuffer, nb::Integer) = read!(io,StringVector(min(nb, nb_available(io)))) -function search(buf::IOBuffer, delim::UInt8) +function findfirst(delim::EqualTo{UInt8}, buf::IOBuffer) p = pointer(buf.data, buf.ptr) - q = @gc_preserve buf ccall(:memchr,Ptr{UInt8},(Ptr{UInt8},Int32,Csize_t),p,delim,nb_available(buf)) + q = @gc_preserve buf ccall(:memchr,Ptr{UInt8},(Ptr{UInt8},Int32,Csize_t),p,delim.x,nb_available(buf)) nb::Int = (q == C_NULL ? 0 : q-p+1) return nb end -function search(buf::GenericIOBuffer, delim::UInt8) +function findfirst(delim::EqualTo{UInt8}, buf::GenericIOBuffer) data = buf.data for i = buf.ptr : buf.size @inbounds b = data[i] - if b == delim + if b == delim.x return i - buf.ptr + 1 end end diff --git a/base/libc.jl b/base/libc.jl index cbe3323c2ef23..fe9fdfb180787 100644 --- a/base/libc.jl +++ b/base/libc.jl @@ -204,7 +204,7 @@ function strptime(fmt::AbstractString, timestr::AbstractString) @static if Sys.isapple() # if we didn't explicitly parse the weekday or year day, use mktime # to fill them in automatically. - if !ismatch(r"([^%]|^)%(a|A|j|w|Ow)", fmt) + if !contains(fmt, r"([^%]|^)%(a|A|j|w|Ow)") ccall(:mktime, Int, (Ref{TmStruct},), tm) end end diff --git a/base/libgit2/types.jl b/base/libgit2/types.jl index 30cc7fdcf068a..7cd6c36f15917 100644 --- a/base/libgit2/types.jl +++ b/base/libgit2/types.jl @@ -894,8 +894,8 @@ function Base.split(ce::ConfigEntry) key = unsafe_string(ce.name) # Determine the positions of the delimiters - subsection_delim = search(key, '.') - name_delim = rsearch(key, '.') + subsection_delim = findfirst(equalto('.'), key) + name_delim = findlast(equalto('.'), key) section = SubString(key, 1, subsection_delim - 1) subsection = SubString(key, subsection_delim + 1, name_delim - 1) diff --git a/base/linalg/blas.jl b/base/linalg/blas.jl index f35f871da5248..a31f084c8078e 100644 --- a/base/linalg/blas.jl +++ b/base/linalg/blas.jl @@ -122,7 +122,7 @@ function check() blas = vendor() if blas == :openblas || blas == :openblas64 openblas_config = openblas_get_config() - openblas64 = ismatch(r".*USE64BITINT.*", openblas_config) + openblas64 = contains(openblas_config, r".*USE64BITINT.*") if Base.USE_BLAS64 != openblas64 if !openblas64 @error """ diff --git a/base/linalg/uniformscaling.jl b/base/linalg/uniformscaling.jl index 97773b9322c61..29bc95fd1403b 100644 --- a/base/linalg/uniformscaling.jl +++ b/base/linalg/uniformscaling.jl @@ -55,7 +55,7 @@ getindex(J::UniformScaling, i::Integer,j::Integer) = ifelse(i==j,J.λ,zero(J.λ) function show(io::IO, J::UniformScaling) s = "$(J.λ)" - if ismatch(r"\w+\s*[\+\-]\s*\w+", s) + if contains(s, r"\w+\s*[\+\-]\s*\w+") s = "($s)" end print(io, "$(typeof(J))\n$s*I") diff --git a/base/markdown/Common/block.jl b/base/markdown/Common/block.jl index a0c4a095d3bae..12b59bf7fc6fc 100644 --- a/base/markdown/Common/block.jl +++ b/base/markdown/Common/block.jl @@ -211,11 +211,11 @@ function admonition(stream::IO, block::MD) let untitled = r"^([a-z]+)$", # !!! titled = r"^([a-z]+) \"(.*)\"$", # !!! "" line = strip(readline(stream)) - if ismatch(untitled, line) + if contains(line, untitled) m = match(untitled, line) # When no title is provided we use CATEGORY_NAME, capitalising it. m.captures[1], ucfirst(m.captures[1]) - elseif ismatch(titled, line) + elseif contains(line, titled) m = match(titled, line) # To have a blank TITLE provide an explicit empty string as TITLE. m.captures[1], m.captures[2] @@ -270,10 +270,10 @@ function list(stream::IO, block::MD) indent = isempty(bullet) ? (return false) : length(bullet) # Calculate the starting number and regex to use for bullet matching. initial, regex = - if ismatch(BULLETS, bullet) + if contains(bullet, BULLETS) # An unordered list. Use `-1` to flag the list as unordered. -1, BULLETS - elseif ismatch(r"^ {0,3}\d+(\.|\))( |$)", bullet) + elseif contains(bullet, r"^ {0,3}\d+(\.|\))( |$)") # An ordered list. Either with `1. ` or `1) ` style numbering. r = contains(bullet, ".") ? r"^ {0,3}(\d+)\.( |$)" : r"^ {0,3}(\d+)\)( |$)" Base.parse(Int, match(r, bullet).captures[1]), r diff --git a/base/markdown/Common/inline.jl b/base/markdown/Common/inline.jl index 276504cc5a13e..0eab3eb0051d6 100644 --- a/base/markdown/Common/inline.jl +++ b/base/markdown/Common/inline.jl @@ -140,7 +140,7 @@ function _is_mailto(s::AbstractString) length(s) < 6 && return false # slicing strings is a bit risky, but this equality check is safe lowercase(s[1:6]) == "mailto:" || return false - return ismatch(_email_regex, s[6:end]) + return contains(s[6:end], _email_regex) end # ––––––––––– diff --git a/base/markdown/render/rst.jl b/base/markdown/render/rst.jl index d4bbaf199a9b5..737cf316c8851 100644 --- a/base/markdown/render/rst.jl +++ b/base/markdown/render/rst.jl @@ -115,7 +115,7 @@ rstinline(io::IO, md::Vector) = !isempty(md) && rstinline(io, md...) # rstinline(io::IO, md::Image) = rstinline(io, ".. image:: ", md.url) function rstinline(io::IO, md::Link) - if ismatch(r":(func|obj|ref|exc|class|const|data):`\.*", md.url) + if contains(md.url, r":(func|obj|ref|exc|class|const|data):`\.*") rstinline(io, md.url) else rstinline(io, "`", md.text, " <", md.url, ">`_") diff --git a/base/markdown/render/terminal/formatting.jl b/base/markdown/render/terminal/formatting.jl index b2bfdf8b56751..d8b3b61158720 100644 --- a/base/markdown/render/terminal/formatting.jl +++ b/base/markdown/render/terminal/formatting.jl @@ -11,7 +11,7 @@ lines(s) = split(s, "\n") # This could really be more efficient function wrapped_lines(io::IO, s::AbstractString; width = 80, i = 0) - if ismatch(r"\n", s) + if contains(s, r"\n") return vcat(map(s->wrapped_lines(io, s, width = width, i = i), split(s, "\n"))...) end ws = words(s) diff --git a/base/methodshow.jl b/base/methodshow.jl index 4ff02dcb77818..7afa482d69f8a 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -11,7 +11,7 @@ function argtype_decl(env, n, sig::DataType, i::Int, nargs, isva::Bool) # -> (ar n = n.args[1] # handle n::T in arg list end s = string(n) - i = search(s,'#') + i = findfirst(equalto('#'), s) if i > 0 s = s[1:i-1] end @@ -202,7 +202,7 @@ function url(m::Method) (m.file == :null || m.file == :string) && return "" file = string(m.file) line = m.line - line <= 0 || ismatch(r"In\[[0-9]+\]", file) && return "" + line <= 0 || contains(file, r"In\[[0-9]+\]") && return "" Sys.iswindows() && (file = replace(file, '\\' => '/')) if inbase(M) if isempty(Base.GIT_VERSION_INFO.commit) diff --git a/base/operators.jl b/base/operators.jl index 9e68815de5afb..2c4a26d2074e5 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -843,3 +843,22 @@ The returned function is of type `Base.EqualTo`. This allows dispatching to specialized methods by using e.g. `f::Base.EqualTo` in a method signature. """ const equalto = EqualTo + +struct OccursIn{T} <: Function + x::T + + OccursIn(x::T) where {T} = new{T}(x) +end + +(f::OccursIn)(y) = y in f.x + +""" + occursin(x) + +Create a function that checks whether its argument is [`in`](@ref) `x`; i.e. returns +`y -> y in x`. + +The returned function is of type `Base.OccursIn`. This allows dispatching to +specialized methods by using e.g. `f::Base.OccursIn` in a method signature. +""" +const occursin = OccursIn diff --git a/base/parse.jl b/base/parse.jl index 303d622035837..e0da3ea303058 100644 --- a/base/parse.jl +++ b/base/parse.jl @@ -281,16 +281,16 @@ function tryparse_internal(::Type{Complex{T}}, s::Union{String,SubString{String} end # find index of ± separating real/imaginary parts (if any) - i₊ = search(s, ('+','-'), i) + i₊ = findnext(occursin(('+','-')), s, i) if i₊ == i # leading ± sign - i₊ = search(s, ('+','-'), i₊+1) + i₊ = findnext(occursin(('+','-')), s, i₊+1) end if i₊ != 0 && s[i₊-1] in ('e','E') # exponent sign - i₊ = search(s, ('+','-'), i₊+1) + i₊ = findnext(occursin(('+','-')), s, i₊+1) end # find trailing im/i/j - iᵢ = rsearch(s, ('m','i','j'), e) + iᵢ = findprev(occursin(('m','i','j')), s, e) if iᵢ > 0 && s[iᵢ] == 'm' # im iᵢ -= 1 if s[iᵢ] != 'i' diff --git a/base/path.jl b/base/path.jl index 2c6c6f10505e7..c602e409d7009 100644 --- a/base/path.jl +++ b/base/path.jl @@ -78,7 +78,7 @@ end if Sys.iswindows() - isabspath(path::String) = ismatch(path_absolute_re, path) + isabspath(path::String) = contains(path, path_absolute_re) else isabspath(path::String) = startswith(path, '/') end @@ -113,7 +113,7 @@ julia> isdirpath("/home/") true ``` """ -isdirpath(path::String) = ismatch(path_directory_re, splitdrive(path)[2]) +isdirpath(path::String) = contains(splitdrive(path)[2], path_directory_re) """ splitdir(path::AbstractString) -> (AbstractString, AbstractString) @@ -218,9 +218,9 @@ function joinpath(a::String, b::String) B, b = splitdrive(b) !isempty(B) && A != B && return string(B,b) C = isempty(B) ? A : B - isempty(a) ? string(C,b) : - ismatch(path_separator_re, a[end:end]) ? string(C,a,b) : - string(C,a,pathsep(a,b),b) + isempty(a) ? string(C,b) : + contains(a[end:end], path_separator_re) ? string(C,a,b) : + string(C,a,pathsep(a,b),b) end joinpath(a::AbstractString, b::AbstractString) = joinpath(String(a), String(b)) diff --git a/base/pkg/read.jl b/base/pkg/read.jl index 721ac55b907df..e68e8457d25e7 100644 --- a/base/pkg/read.jl +++ b/base/pkg/read.jl @@ -18,7 +18,7 @@ function available(names=readdir("METADATA")) versdir = joinpath("METADATA", pkg, "versions") isdir(versdir) || continue for ver in readdir(versdir) - ismatch(Base.VERSION_REGEX, ver) || continue + contains(ver, Base.VERSION_REGEX) || continue isfile(versdir, ver, "sha1") || continue haskey(pkgs,pkg) || (pkgs[pkg] = Dict{VersionNumber,Available}()) pkgs[pkg][VersionNumber(ver)] = Available( @@ -39,7 +39,7 @@ function latest(names=readdir("METADATA")) isdir(versdir) || continue pkgversions = VersionNumber[] for ver in readdir(versdir) - ismatch(Base.VERSION_REGEX, ver) || continue + contains(ver, Base.VERSION_REGEX) || continue isfile(versdir, ver, "sha1") || continue push!(pkgversions, VersionNumber(ver)) end @@ -114,7 +114,7 @@ function ispinned(prepo::LibGit2.GitRepo) LibGit2.isattached(prepo) || return false br = LibGit2.branch(prepo) # note: regex is based on the naming scheme used in Entry.pin() - return ismatch(r"^pinned\.[0-9a-f]{8}\.tmp$", br) + return contains(br, r"^pinned\.[0-9a-f]{8}\.tmp$") end function installed_version(pkg::AbstractString, prepo::LibGit2.GitRepo, avail::Dict=available(pkg)) diff --git a/base/pkg/reqs.jl b/base/pkg/reqs.jl index 57a539e1aab48..7bc9db969bbef 100644 --- a/base/pkg/reqs.jl +++ b/base/pkg/reqs.jl @@ -26,7 +26,7 @@ struct Requirement <: Line end isempty(fields) && throw(PkgError("invalid requires entry: $content")) package = popfirst!(fields) - all(field->ismatch(Base.VERSION_REGEX, field), fields) || + all(field->contains(field, Base.VERSION_REGEX), fields) || throw(PkgError("invalid requires entry for $package: $content")) versions = map(VersionNumber, fields) issorted(versions) || throw(PkgError("invalid requires entry for $package: $content")) @@ -58,7 +58,7 @@ function read(readable::Vector{<:AbstractString}) lines = Line[] for line in readable line = chomp(line) - push!(lines, ismatch(r"^\s*(?:#|$)", line) ? Comment(line) : Requirement(line)) + push!(lines, contains(line, r"^\s*(?:#|$)") ? Comment(line) : Requirement(line)) end return lines end @@ -66,7 +66,7 @@ end function read(readable::Union{IO,Base.AbstractCmd}) lines = Line[] for line in eachline(readable) - push!(lines, ismatch(r"^\s*(?:#|$)", line) ? Comment(line) : Requirement(line)) + push!(lines, contains(line, r"^\s*(?:#|$)") ? Comment(line) : Requirement(line)) end return lines end diff --git a/base/precompile.jl b/base/precompile.jl index a9d5dd1367915..51acceafbed74 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -181,16 +181,16 @@ precompile(Tuple{typeof(Base.REPL.ip_matches_func), Ptr{Cvoid}, Symbol}) precompile(Tuple{typeof(Base.throw_boundserror), Array{Ptr{Cvoid}, 1}, Tuple{Base.UnitRange{Int64}}}) precompile(Tuple{typeof(Base.unsafe_copyto!), Array{Ptr{Cvoid}, 1}, Int64, Array{Ptr{Cvoid}, 1}, Int64, Int64}) precompile(Tuple{Type{Base.Channel{Any}}, Int64}) -precompile(Tuple{typeof(Base.rsearch), String, UInt8, Int64}) -precompile(Tuple{typeof(Base.rsearch), String, Char, Int64}) -precompile(Tuple{typeof(Base.rsearch), Array{UInt8, 1}, UInt8, Int64}) +precompile(Tuple{typeof(Base._rsearch), String, UInt8, Int64}) +precompile(Tuple{typeof(Base._rsearch), String, Char, Int64}) +precompile(Tuple{typeof(Base._rsearch), Array{UInt8, 1}, UInt8, Int64}) precompile(Tuple{typeof(Base._rsearchindex), Array{UInt8, 1}, Array{UInt8, 1}, Int64}) precompile(Tuple{typeof(Base._rsearch), Array{UInt8, 1}, Array{UInt8, 1}, Int64}) -precompile(Tuple{typeof(Base.rsearch), Array{Int8, 1}, UInt8, Int64}) +precompile(Tuple{typeof(Base._rsearch), Array{Int8, 1}, UInt8, Int64}) precompile(Tuple{typeof(Base._rsearchindex), Array{Int8, 1}, Array{UInt8, 1}, Int64}) precompile(Tuple{typeof(Base._rsearch), Array{Int8, 1}, Array{UInt8, 1}, Int64}) -precompile(Tuple{typeof(Base.rsearch), Array{UInt8, 1}, Char, Int64}) -precompile(Tuple{typeof(Base.rsearch), Array{Int8, 1}, Char, Int64}) +precompile(Tuple{typeof(Base._rsearch), Array{UInt8, 1}, Char, Int64}) +precompile(Tuple{typeof(Base._rsearch), Array{Int8, 1}, Char, Int64}) precompile(Tuple{typeof(Base.splice!), Array{Base.Multimedia.AbstractDisplay, 1}, Int64, Array{Any, 1}}) precompile(Tuple{typeof(Core.Inference.isbits), Base.LineEdit.EmptyCompletionProvider}) precompile(Tuple{typeof(Core.Inference.isbits), Base.LineEdit.EmptyHistoryProvider}) @@ -547,7 +547,7 @@ 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.rsearch), 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{Nothing, Nothing, Nothing}}) precompile(Tuple{typeof(Base.isidentifier), Base.SubString{String}}) @@ -621,11 +621,10 @@ precompile(Tuple{typeof(Base.unique), Array{String, 1}}) precompile(Tuple{typeof(Base.REPL.beforecursor), Base.GenericIOBuffer{Array{UInt8, 1}}}) precompile(Tuple{typeof(Base.REPLCompletions.completions), String, Int64}) precompile(Tuple{typeof(Base.incomplete_tag), Symbol}) -precompile(Tuple{typeof(Base.rsearchindex), String, String, Int64}) precompile(Tuple{typeof(Base._rsearch), String, String, Int64}) precompile(Tuple{typeof(Base.pushfirst!), Array{Base.SubString{String}, 1}, Base.SubString{String}}) precompile(Tuple{typeof(Base.startswith), String, Base.SubString{String}}) -precompile(Tuple{typeof(Base.rsearch), String, Array{Char, 1}}) +precompile(Tuple{typeof(Base._rsearch), String, Array{Char, 1}}) precompile(Tuple{getfield(Base, Symbol("#kw##rsplit")), Array{Any, 1}, typeof(Base.rsplit), String, String}) precompile(Tuple{typeof(Base.sort!), Array{String, 1}, Base.Sort.MergeSortAlg, Base.Order.ForwardOrdering}) precompile(Tuple{typeof(Base.sort!), Array{String, 1}, Int64, Int64, Base.Sort.InsertionSortAlg, Base.Order.ForwardOrdering}) @@ -917,7 +916,6 @@ precompile(Tuple{typeof(Base.Markdown.parseinline), Base.GenericIOBuffer{Array{U precompile(Tuple{typeof(Base.Markdown.config), Base.Markdown.MD}) precompile(Tuple{typeof(Base.Markdown.parseinline), Base.GenericIOBuffer{Array{UInt8, 1}}, Base.Markdown.MD, Base.Markdown.Config}) precompile(Tuple{typeof(Base.Markdown.list), Base.GenericIOBuffer{Array{UInt8, 1}}, Base.Markdown.MD}) -precompile(Tuple{typeof(Base.searchindex), String, String}) precompile(Tuple{typeof(Base._searchindex), Base.SubString{String}, String, Int64}) precompile(Tuple{getfield(Base.Markdown, Symbol("#kw##skipwhitespace")), Array{Any, 1}, typeof(Base.Markdown.skipwhitespace), Base.GenericIOBuffer{Array{UInt8, 1}}}) precompile(Tuple{typeof(Base.ht_keyindex), Base.Dict{Symbol, Base.Markdown.Config}, Symbol}) @@ -1156,7 +1154,7 @@ precompile(Tuple{typeof(Base.resize!), Array{Base.Semaphore, 1}, Int64}) precompile(Tuple{typeof(Base.acquire), Base.Semaphore}) precompile(Tuple{typeof(Base.release), Base.Semaphore}) precompile(Tuple{typeof(Base.isreadable), Base.PipeEndpoint}) -precompile(Tuple{typeof(Base.search), Base.GenericIOBuffer{Array{UInt8, 1}}, UInt8}) +precompile(Tuple{typeof(Base.findfirst), UInt8, Base.GenericIOBuffer{Array{UInt8, 1}}}) precompile(Tuple{typeof(Base.start_reading), Base.PipeEndpoint}) precompile(Tuple{typeof(Base.wait_readbyte), Base.PipeEndpoint, UInt8}) precompile(Tuple{typeof(Base.readuntil), Base.PipeEndpoint, UInt8}) diff --git a/base/random/misc.jl b/base/random/misc.jl index 6c20d1a943d35..68abece65b197 100644 --- a/base/random/misc.jl +++ b/base/random/misc.jl @@ -432,7 +432,7 @@ let groupings = [1:8; 10:13; 15:18; 20:23; 25:36] function UUID(s::AbstractString) s = Base.Unicode.lowercase(s) - if !ismatch(r"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$", s) + if !contains(s, r"^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$") throw(ArgumentError("Malformed UUID string")) end diff --git a/base/range.jl b/base/range.jl index b46bad0ac07ee..2219e56033853 100644 --- a/base/range.jl +++ b/base/range.jl @@ -705,7 +705,7 @@ function intersect(r1::AbstractRange, r2::AbstractRange, r3::AbstractRange, r::A i end -# findin (the index of intersection) +# _findin (the index of intersection) function _findin(r::AbstractRange{<:Integer}, span::AbstractUnitRange{<:Integer}) local ifirst local ilast @@ -724,17 +724,7 @@ function _findin(r::AbstractRange{<:Integer}, span::AbstractUnitRange{<:Integer} ifirst = fr >= fspan ? 1 : length(r)+1 ilast = fr <= lspan ? length(r) : 0 end - ifirst, ilast -end - -function findin(r::AbstractUnitRange{<:Integer}, span::AbstractUnitRange{<:Integer}) - ifirst, ilast = _findin(r, span) - ifirst:ilast -end - -function findin(r::AbstractRange{<:Integer}, span::AbstractUnitRange{<:Integer}) - ifirst, ilast = _findin(r, span) - ifirst:1:ilast + r isa AbstractUnitRange ? (ifirst:ilast) : (ifirst:1:ilast) end ## linear operations on ranges ## diff --git a/base/regex.jl b/base/regex.jl index 726c33f77f02f..565e93844c999 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -141,39 +141,19 @@ function getindex(m::RegexMatch, name::Symbol) end getindex(m::RegexMatch, name::AbstractString) = m[Symbol(name)] -""" - ismatch(r::Regex, s::AbstractString) -> Bool - -Test whether a string contains a match of the given regular expression. - -# Examples -```jldoctest -julia> rx = r"a.a" -r"a.a" - -julia> ismatch(rx, "aba") -true - -julia> ismatch(rx, "abba") -false - -julia> rx("aba") -true -``` -""" -function ismatch(r::Regex, s::AbstractString, offset::Integer=0) +function contains(s::AbstractString, r::Regex, offset::Integer=0) compile(r) return PCRE.exec(r.regex, String(s), offset, r.match_options, r.match_data) end -function ismatch(r::Regex, s::SubString, offset::Integer=0) +function contains(s::SubString, r::Regex, offset::Integer=0) compile(r) return PCRE.exec(r.regex, s, offset, r.match_options, r.match_data) end -(r::Regex)(s) = ismatch(r, s) +(r::Regex)(s) = contains(s, r) """ match(r::Regex, s::AbstractString[, idx::Integer[, addopts]]) @@ -285,7 +265,8 @@ end matchall(re::Regex, str::SubString, overlap::Bool=false) = matchall(re, String(str), overlap) -function search(str::Union{String,SubString}, re::Regex, idx::Integer) +# TODO: return only start index and update deprecation +function findnext(re::Regex, str::Union{String,SubString}, idx::Integer) if idx > nextind(str,endof(str)) throw(BoundsError()) end @@ -294,10 +275,10 @@ function search(str::Union{String,SubString}, re::Regex, idx::Integer) PCRE.exec(re.regex, str, idx-1, opts, re.match_data) ? ((Int(re.ovec[1])+1):prevind(str,Int(re.ovec[2])+1)) : (0:-1) end -search(s::AbstractString, r::Regex, idx::Integer) = throw(ArgumentError( +findnext(r::Regex, s::AbstractString, idx::Integer) = throw(ArgumentError( "regex search is only available for the String type; use String(s) to convert" )) -search(s::AbstractString, r::Regex) = search(s,r,start(s)) +findfirst(r::Regex, s::AbstractString) = findnext(r,s,start(s)) struct SubstitutionString{T<:AbstractString} <: AbstractString string::T diff --git a/base/repl/LineEdit.jl b/base/repl/LineEdit.jl index 0bf91d142daf0..7f92d6d047b4d 100644 --- a/base/repl/LineEdit.jl +++ b/base/repl/LineEdit.jl @@ -580,11 +580,11 @@ end # of the line. function edit_move_up(buf::IOBuffer) - npos = rsearch(buf.data, '\n', position(buf)) + npos = findprev(equalto(UInt8('\n')), buf.data, position(buf)) npos == 0 && return false # we're in the first line # We're interested in character count, not byte count offset = length(content(buf, npos => position(buf))) - npos2 = rsearch(buf.data, '\n', npos-1) + npos2 = findprev(equalto(UInt8('\n')), buf.data, npos-1) seek(buf, npos2) for _ = 1:offset pos = position(buf) @@ -603,10 +603,10 @@ function edit_move_up(s) end function edit_move_down(buf::IOBuffer) - npos = rsearch(buf.data[1:buf.size], '\n', position(buf)) + npos = findprev(equalto(UInt8('\n')), buf.data[1:buf.size], position(buf)) # We're interested in character count, not byte count offset = length(String(buf.data[(npos+1):(position(buf))])) - npos2 = search(buf.data[1:buf.size], '\n', position(buf)+1) + npos2 = findnext(equalto(UInt8('\n')), buf.data[1:buf.size], position(buf)+1) if npos2 == 0 #we're in the last line return false end @@ -1849,7 +1849,7 @@ function move_line_start(s::MIState) if s.key_repeats > 0 move_input_start(s) else - seek(buf, rsearch(buf.data, '\n', curpos)) + seek(buf, findprev(equalto(UInt8('\n')), buf.data, curpos)) end end @@ -1862,7 +1862,7 @@ end function move_line_end(buf::IOBuffer) eof(buf) && return - pos = search(buf.data, '\n', position(buf)+1) + pos = findnext(equalto(UInt8('\n')), buf.data, position(buf)+1) if pos == 0 move_input_end(buf) return diff --git a/base/repl/REPL.jl b/base/repl/REPL.jl index 34a6a6de923de..033398e5ecb83 100644 --- a/base/repl/REPL.jl +++ b/base/repl/REPL.jl @@ -617,14 +617,15 @@ function history_search(hist::REPLHistoryProvider, query_buffer::IOBuffer, respo !skip_current && searchdata == response_str[a:b] && return true - searchfunc, searchstart, skipfunc = backwards ? (rsearch, b, prevind) : - (search, a, nextind) + searchfunc1, searchfunc2, searchstart, skipfunc = backwards ? + (findlast, findprev, b, prevind) : + (findfirst, findnext, a, nextind) skip_current && (searchstart = skipfunc(response_str, searchstart)) # Start searching # First the current response buffer if 1 <= searchstart <= endof(response_str) - match = searchfunc(response_str, searchdata, searchstart) + match = searchfunc2(searchdata, response_str, searchstart) if match != 0:-1 seek(response_buffer, first(match) - 1) return true @@ -635,7 +636,7 @@ function history_search(hist::REPLHistoryProvider, query_buffer::IOBuffer, respo idxs = backwards ? ((hist.cur_idx-1):-1:1) : ((hist.cur_idx+1):length(hist.history)) for idx in idxs h = hist.history[idx] - match = searchfunc(h, searchdata) + match = searchfunc1(searchdata, h) if match != 0:-1 && h != response_str && haskey(hist.mode_mapping, hist.modes[idx]) truncate(response_buffer, 0) write(response_buffer, h) @@ -887,7 +888,7 @@ function setup_interface( sbuffer = LineEdit.buffer(s) curspos = position(sbuffer) seek(sbuffer, 0) - shouldeval = (nb_available(sbuffer) == curspos && search(sbuffer, UInt8('\n')) == 0) + shouldeval = (nb_available(sbuffer) == curspos && findfirst(equalto(UInt8('\n')), sbuffer) == 0) seek(sbuffer, curspos) if curspos == 0 # if pasting at the beginning, strip leading whitespace @@ -1049,7 +1050,7 @@ input_color(r::StreamREPL) = r.input_color # heuristic function to decide if the presence of a semicolon # at the end of the expression was intended for suppressing output function ends_with_semicolon(line::AbstractString) - match = rsearch(line, ';') + match = findlast(equalto(';'), line) if match != 0 # state for comment parser, assuming that the `;` isn't in a string or comment # so input like ";#" will still thwart this to give the wrong (anti-conservative) answer diff --git a/base/repl/REPLCompletions.jl b/base/repl/REPLCompletions.jl index d5be637da4380..4c88d236fee6f 100644 --- a/base/repl/REPLCompletions.jl +++ b/base/repl/REPLCompletions.jl @@ -40,7 +40,7 @@ function complete_symbol(sym, ffunc) lookup_module = true t = Union{} - if rsearch(sym, non_identifier_chars) < rsearch(sym, '.') + if findlast(occursin(non_identifier_chars), sym) < findlast(equalto('.'), sym) # Find module lookup_name, name = rsplit(sym, ".", limit=2) @@ -116,7 +116,7 @@ function complete_keyword(s::Union{String,SubString{String}}) end function complete_path(path::AbstractString, pos; use_envpath=false) - if Base.Sys.isunix() && ismatch(r"^~(?:/|$)", path) + if Base.Sys.isunix() && contains(path, r"^~(?:/|$)") # if the path is just "~", don't consider the expanded username as a prefix if path == "~" dir, prefix = homedir(), "" @@ -258,7 +258,7 @@ function find_start_brace(s::AbstractString; c_start='(', c_end=')') end braces != 1 && return 0:-1, -1 method_name_end = reverseind(s, i) - startind = nextind(s, rsearch(s, non_identifier_chars, method_name_end)) + startind = nextind(s, findprev(occursin(non_identifier_chars), s, method_name_end)) return (startind:endof(s), method_name_end) end @@ -406,15 +406,15 @@ function afterusing(string::String, startpos::Int) str = string[1:prevind(string,startpos)] isempty(str) && return false rstr = reverse(str) - r = search(rstr, r"\s(gnisu|tropmi)\b") + r = findfirst(r"\s(gnisu|tropmi)\b", rstr) isempty(r) && return false fr = reverseind(str, last(r)) - return ismatch(r"^\b(using|import)\s*((\w+[.])*\w+\s*,\s*)*$", str[fr:end]) + return contains(str[fr:end], r"^\b(using|import)\s*((\w+[.])*\w+\s*,\s*)*$") end function bslash_completions(string, pos) - slashpos = rsearch(string, '\\', pos) - if (rsearch(string, bslash_separators, pos) < slashpos && + slashpos = findprev(equalto('\\'), string, pos) + if (findprev(occursin(bslash_separators), string, pos) < slashpos && !(1 < slashpos && (string[prevind(string, slashpos)]=='\\'))) # latex / emoji symbol substitution s = string[slashpos:pos] @@ -459,7 +459,7 @@ function dict_identifier_key(str,tag) # Avoid `isdefined(::Array, ::Symbol)` isa(obj, Array) && return (nothing, nothing, nothing) end - begin_of_key = first(search(str, r"\S", nextind(str, end_of_identifier) + 1)) # 1 for [ + begin_of_key = first(findnext(r"\S", str, nextind(str, end_of_identifier) + 1)) # 1 for [ begin_of_key==0 && return (true, nothing, nothing) partial_key = str[begin_of_key:end] (isa(obj, AbstractDict) && length(obj) < 1e6) || return (true, nothing, nothing) @@ -533,8 +533,8 @@ function completions(string, pos) return String[], 0:-1, false end - dotpos = rsearch(string, '.', pos) - startpos = nextind(string, rsearch(string, non_identifier_chars, pos)) + dotpos = findprev(equalto('.'), string, pos) + startpos = nextind(string, findprev(occursin(non_identifier_chars), string, pos)) ffunc = (mod,x)->true suggestions = String[] diff --git a/base/repl/latex_symbols.jl b/base/repl/latex_symbols.jl index a4792522a8e7a..c3719e49c7149 100644 --- a/base/repl/latex_symbols.jl +++ b/base/repl/latex_symbols.jl @@ -24,7 +24,7 @@ for c in child_nodes(root(xdoc)) id = attribute(ce, "id") U = string(map(s -> Char(parse(Int, s, 16)), split(id[2:end], "-"))...) - if ismatch(r"^\\[A-Za-z]+$",L) && !isa(U,String) + if contains(L, r"^\\[A-Za-z]+$") && !isa(U,String) if L in Ls println("# duplicated symbol $L ($id)") else diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index b864016b94f11..1d2516c01c133 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -1276,6 +1276,8 @@ function find(p::Function, S::SparseMatrixCSC) I, J = _findn(p, S) return Base._sub2ind(sz, I, J) end +find(p::Base.OccursIn, x::SparseMatrixCSC) = + invoke(find, Tuple{Base.OccursIn, AbstractArray}, p, x) findn(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = _findn(x->true, S) diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 4ee09d93a8080..4d86349377166 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -705,6 +705,8 @@ function find(p::Function, x::SparseVector{<:Any,Ti}) where Ti return I end +find(p::Base.OccursIn, x::SparseVector{<:Any,Ti}) where {Ti} = + invoke(find, Tuple{Base.OccursIn, AbstractArray}, p, x) function findnz(x::SparseVector{Tv,Ti}) where {Tv,Ti} numnz = nnz(x) diff --git a/base/stream.jl b/base/stream.jl index 5a0143da2534d..58bf399afb26b 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -271,13 +271,13 @@ end function wait_readbyte(x::LibuvStream, c::UInt8) if isopen(x) # fast path - search(x.buffer, c) > 0 && return + findfirst(equalto(c), x.buffer) > 0 && return else return end preserve_handle(x) try - while isopen(x) && search(x.buffer, c) <= 0 + while isopen(x) && findfirst(equalto(c), x.buffer) <= 0 start_reading(x) # ensure we are reading wait(x.readnotify) end @@ -1237,7 +1237,7 @@ end show(io::IO, s::BufferStream) = print(io,"BufferStream() bytes waiting:",nb_available(s.buffer),", isopen:", s.is_open) function wait_readbyte(s::BufferStream, c::UInt8) - while isopen(s) && search(s.buffer,c) <= 0 + while isopen(s) && findfirst(equalto(c), s.buffer) <= 0 wait(s.r_c) end end diff --git a/base/strings/search.jl b/base/strings/search.jl index f920b77520252..8002e9fdd59e1 100644 --- a/base/strings/search.jl +++ b/base/strings/search.jl @@ -1,20 +1,26 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -function search(s::String, c::Char, i::Integer = 1) +function findnext(pred::EqualTo{Char}, s::String, i::Integer) if i < 1 || i > sizeof(s) i == sizeof(s) + 1 && return 0 throw(BoundsError(s, i)) end @inbounds isvalid(s, i) || string_index_err(s, i) - c ≤ '\x7f' && return search(s, c % UInt8, i) + c = pred.x + c ≤ '\x7f' && return _search(s, c % UInt8, i) while true - i = search(s, first_utf8_byte(c), i) + i = _search(s, first_utf8_byte(c), i) (i == 0 || s[i] == c) && return i i = next(s, i)[2] end end -function search(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = 1) +findfirst(pred::EqualTo{<:Union{Int8,UInt8}}, a::ByteArray) = _search(a, pred.x) + +findnext(pred::EqualTo{<:Union{Int8,UInt8}}, a::ByteArray, i::Integer) = + _search(a, pred.x, i) + +function _search(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = 1) if i < 1 throw(BoundsError(a, i)) end @@ -27,25 +33,31 @@ function search(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = 1 q == C_NULL ? 0 : Int(q-p+1) end -function search(a::ByteArray, b::Char, i::Integer = 1) +function _search(a::ByteArray, b::Char, i::Integer = 1) if isascii(b) - search(a,UInt8(b),i) + _search(a,UInt8(b),i) else - search(a,unsafe_wrap(Vector{UInt8},string(b)),i).start + _search(a,unsafe_wrap(Vector{UInt8},string(b)),i).start end end -function rsearch(s::String, c::Char, i::Integer = sizeof(s)) - c ≤ '\x7f' && return rsearch(s, c % UInt8, i) +function findprev(pred::EqualTo{Char}, s::String, i::Integer) + c = pred.x + c ≤ '\x7f' && return _rsearch(s, c % UInt8, i) b = first_utf8_byte(c) while true - i = rsearch(s, b, i) + i = _rsearch(s, b, i) (i == 0 || s[i] == c) && return i i = prevind(s, i) end end -function rsearch(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = sizeof(s)) +findlast(pred::EqualTo{<:Union{Int8,UInt8}}, a::ByteArray) = _rsearch(a, pred.x) + +findprev(pred::EqualTo{<:Union{Int8,UInt8}}, a::ByteArray, i::Integer) = + _rsearch(a, pred.x, i) + +function _rsearch(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = sizeof(a)) if i < 1 return i == 0 ? 0 : throw(BoundsError(a, i)) end @@ -58,65 +70,60 @@ function rsearch(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = q == C_NULL ? 0 : Int(q-p+1) end -function rsearch(a::ByteArray, b::Char, i::Integer = length(a)) +function _rsearch(a::ByteArray, b::Char, i::Integer = length(a)) if isascii(b) - rsearch(a,UInt8(b),i) + _rsearch(a,UInt8(b),i) else - rsearch(a,unsafe_wrap(Vector{UInt8},string(b)),i).start + _rsearch(a,unsafe_wrap(Vector{UInt8},string(b)),i).start end end -const Chars = Union{Char,Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}} - """ - search(string::AbstractString, chars::Chars, [start::Integer]) - -Search for the first occurrence of the given characters within the given string. The second -argument may be a single character, a vector or a set of characters, a string, or a regular -expression (though regular expressions are only allowed on contiguous strings, such as ASCII -or UTF-8 strings). The third argument optionally specifies a starting index. The return -value is a range of indices where the matching sequence is found, such that `s[search(s,x)] == x`: + findfirst(pattern::AbstractString, string::AbstractString) + findfirst(pattern::Regex, string::String) -`search(string, "substring")` = `start:end` such that `string[start:end] == "substring"`, or -`0:-1` if unmatched. - -`search(string, 'c')` = `index` such that `string[index] == 'c'`, or `0` if unmatched. +Find the first occurrence of `pattern` in `string`. Equivalent to +[`findnext(pattern, string, start(s))`](@ref). # Examples ```jldoctest -julia> search("Hello to the world", "z") +julia> findfirst("z", "Hello to the world") 0:-1 -julia> search("JuliaLang","Julia") +julia> findfirst("Julia", "JuliaLang") 1:5 ``` """ -function search(s::AbstractString, c::Chars, i::Integer) +findfirst(pattern::AbstractString, string::AbstractString) = + findnext(pattern, string, start(string)) + +# AbstractString implementation of the generic findnext interface +function findnext(testf::Function, s::AbstractString, i::Integer) z = ncodeunits(s) + 1 - isempty(c) && return 1 ≤ i ≤ z ? i : throw(BoundsError(s, i)) 1 ≤ i ≤ z || throw(BoundsError(s, i)) @inbounds i == z || isvalid(s, i) || string_index_err(s, i) while !done(s,i) d, j = next(s,i) - if d in c + if testf(d) return i end i = j end return 0 end -search(s::AbstractString, c::Chars) = search(s,c,start(s)) -in(c::Char, s::AbstractString) = (search(s,c)!=0) +in(c::Char, s::AbstractString) = (findfirst(equalto(c),s)!=0) -function _searchindex(s, t, i) +function _searchindex(s::Union{AbstractString,ByteArray}, + t::Union{AbstractString,Char,Int8,UInt8}, + i::Integer) if isempty(t) return 1 <= i <= nextind(s,endof(s)) ? i : throw(BoundsError(s, i)) end t1, j2 = next(t,start(t)) while true - i = search(s,t1,i) + i = findnext(equalto(t1),s,i) if i == 0 return 0 end c, ii = next(s,i) j = j2; k = ii @@ -140,7 +147,7 @@ function _searchindex(s, t, i) end end -_searchindex(s, t::Char, i) = search(s, t, i) +_searchindex(s::AbstractString, t::Char, i::Integer) = findnext(equalto(t), s, i) function _search_bloom_mask(c) UInt64(1) << (c & 63) @@ -149,7 +156,13 @@ end _nthbyte(s::String, i) = codeunit(s, i) _nthbyte(a::Union{AbstractVector{UInt8},AbstractVector{Int8}}, i) = a[i] -function _searchindex(s::Union{String,ByteArray}, t::Union{String,ByteArray}, i) +function _searchindex(s::String, t::String, i::Integer) + # Check for fast case of a single byte + endof(t) == 1 && return findnext(equalto(t[1]), s, i) + _searchindex(unsafe_wrap(Vector{UInt8},s), unsafe_wrap(Vector{UInt8},t), i) +end + +function _searchindex(s::ByteArray, t::ByteArray, i::Integer) n = sizeof(t) m = sizeof(s) @@ -158,7 +171,7 @@ function _searchindex(s::Union{String,ByteArray}, t::Union{String,ByteArray}, i) elseif m == 0 return 0 elseif n == 1 - return search(s, _nthbyte(t,1), i) + return findnext(equalto(_nthbyte(t,1)), s, i) end w = m - n @@ -210,66 +223,66 @@ function _searchindex(s::Union{String,ByteArray}, t::Union{String,ByteArray}, i) 0 end -searchindex(s::ByteArray, t::ByteArray, i) = _searchindex(s,t,i) +function _search(s::Union{AbstractString,ByteArray}, + t::Union{AbstractString,Char,Int8,UInt8}, + i::Integer) + idx = _searchindex(s,t,i) + if isempty(t) + idx:idx-1 + else + idx:(idx > 0 ? idx + endof(t) - 1 : -1) + end +end """ - searchindex(s::AbstractString, substring, [start::Integer]) + findnext(pattern::AbstractString, string::AbstractString, start::Integer) + findnext(pattern::Regex, string::String, start::Integer) + +Find the next occurrence of `pattern` in `string` starting at position `start`. +`pattern` can be either a string, or a regular expression, in which case `string` +must be of type `String`. -Similar to [`search`](@ref), but return only the start index at which -the substring is found, or `0` if it is not. +The return value is a range of indexes where the matching sequence is found, such that +`s[findnext(x, s, i)] == x`: + +`findnext("substring", string, i)` = `start:end` such that +`string[start:end] == "substring"`, or `0:-1` if unmatched. # Examples ```jldoctest -julia> searchindex("Hello to the world", "z") -0 +julia> findnext("z", "Hello to the world", 1) +0:-1 -julia> searchindex("JuliaLang","Julia") -1 +julia> findnext("o", "Hello to the world", 6) +8:8 -julia> searchindex("JuliaLang","Lang") -6 +julia> findnext("Julia", "JuliaLang", 2) +1:5 ``` """ -searchindex(s::AbstractString, t::AbstractString, i::Integer) = _searchindex(s,t,i) -searchindex(s::AbstractString, t::AbstractString) = searchindex(s,t,start(s)) -searchindex(s::AbstractString, c::Char, i::Integer) = _searchindex(s,c,i) -searchindex(s::AbstractString, c::Char) = searchindex(s,c,start(s)) - -function searchindex(s::String, t::String, i::Integer=1) - # Check for fast case of a single byte - # (for multi-byte UTF-8 sequences, use searchindex on byte arrays instead) - if endof(t) == 1 - search(s, t[1], i) - else - _searchindex(s, t, i) - end -end - -function _search(s, t, i::Integer) - idx = searchindex(s,t,i) - if isempty(t) - idx:idx-1 - else - idx:(idx > 0 ? idx + endof(t) - 1 : -1) - end -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) +findnext(t::AbstractString, s::AbstractString, i::Integer) = _search(s, t, i) """ - rsearch(s::AbstractString, chars::Chars, [start::Integer]) + findlast(pattern::AbstractString, string::AbstractString) + findlast(pattern::Regex, string::String) -Similar to [`search`](@ref), but returning the last occurrence of the given characters within the -given string, searching in reverse from `start`. +Find the last occurrence of `pattern` in `string`. Equivalent to +[`findlast(pattern, string, endof(s))`](@ref). # Examples ```jldoctest -julia> rsearch("aaabbb","b") -6:6 +julia> findlast("o", "Hello to the world") +15:15 + +julia> findfirst("Julia", "JuliaLang") +1:5 ``` """ -function rsearch(s::AbstractString, c::Chars, i::Integer=start(s)) +findlast(pattern::AbstractString, string::AbstractString) = + findprev(pattern, string, endof(string)) + +# AbstractString implementation of the generic findprev interface +function findprev(testf::Function, s::AbstractString, i::Integer) if i < 1 return i == 0 ? 0 : throw(BoundsError(s, i)) end @@ -280,21 +293,23 @@ function rsearch(s::AbstractString, c::Chars, i::Integer=start(s)) # r[reverseind(r,i)] == reverse(r)[i] == s[i] # s[reverseind(s,j)] == reverse(s)[j] == r[j] r = reverse(s) - j = search(r, c, reverseind(r, i)) + j = findnext(testf, r, reverseind(r, i)) j == 0 ? 0 : reverseind(s, j) end -function _rsearchindex(s, t, i) +function _rsearchindex(s::AbstractString, + t::Union{AbstractString,Char,Int8,UInt8}, + i::Integer) if isempty(t) return 1 <= i <= nextind(s, endof(s)) ? i : throw(BoundsError(s, i)) end - t = reverse(t) + t = t isa AbstractString ? reverse(t) : t rs = reverse(s) l = endof(s) t1, j2 = next(t, start(t)) while true - i = rsearch(s, t1, i) + i = findprev(equalto(t1), s, i) i == 0 && return 0 c, ii = next(rs, reverseind(rs, i)) j = j2; k = ii @@ -316,7 +331,23 @@ function _rsearchindex(s, t, i) end end -function _rsearchindex(s::Union{String,ByteArray}, t::Union{String,ByteArray}, k) +function _rsearchindex(s::String, t::String, i::Integer) + # Check for fast case of a single byte + if endof(t) == 1 + return findprev(equalto(t[1]), s, i) + elseif endof(t) != 0 + j = i ≤ ncodeunits(s) ? nextind(s, i)-1 : i + return _rsearchindex(unsafe_wrap(Vector{UInt8}, s), unsafe_wrap(Vector{UInt8}, t), j) + elseif i > sizeof(s) + return 0 + elseif i == 0 + return 1 + else + return i + end +end + +function _rsearchindex(s::ByteArray, t::ByteArray, k::Integer) n = sizeof(t) m = sizeof(s) @@ -325,7 +356,7 @@ function _rsearchindex(s::Union{String,ByteArray}, t::Union{String,ByteArray}, k elseif m == 0 return 0 elseif n == 1 - return rsearch(s, _nthbyte(t,1), k) + return findprev(equalto(_nthbyte(t,1)), s, k) end w = m - n @@ -377,75 +408,69 @@ function _rsearchindex(s::Union{String,ByteArray}, t::Union{String,ByteArray}, k 0 end -rsearchindex(s::ByteArray, t::ByteArray, i::Integer) = _rsearchindex(s,t,i) +function _rsearch(s::Union{AbstractString,ByteArray}, + t::Union{AbstractString,Char,Int8,UInt8}, + i::Integer) + idx = _rsearchindex(s,t,i) + if isempty(t) + idx:idx-1 + else + idx:(idx > 0 ? idx + endof(t) - 1 : -1) + end +end """ - rsearchindex(s::AbstractString, substring, [start::Integer]) + findprev(pattern::AbstractString, string::AbstractString, start::Integer) + findprev(pattern::Regex, string::String, start::Integer) -Similar to [`rsearch`](@ref), but return only the start index at which the substring is found, or `0` if it is not. +Find the previous occurrence of `pattern` in `string` starting at position `start`. +`pattern` can be either a string, or a regular expression, in which case `string` +must be of type `String`. + +The return value is a range of indexes where the matching sequence is found, such that +`s[findprev(x, s, i)] == x`: + +`findprev("substring", string, i)` = `start:end` such that +`string[start:end] == "substring"`, or `0:-1` if unmatched. # Examples ```jldoctest -julia> rsearchindex("aaabbb","b") -6 +julia> findprev("z", "Hello to the world", 18) +0:-1 -julia> rsearchindex("aaabbb","a") -3 +julia> findprev("o", "Hello to the world", 18) +15:15 + +julia> findprev("Julia", "JuliaLang", 6) +1:5 ``` """ -rsearchindex(s::AbstractString, t::AbstractString, i::Integer) = _rsearchindex(s,t,i) -rsearchindex(s::AbstractString, t::AbstractString) = (isempty(s) && isempty(t)) ? 1 : rsearchindex(s,t,endof(s)) - -function rsearchindex(s::String, t::String) - # Check for fast case of a single byte - # (for multi-byte UTF-8 sequences, use rsearchindex instead) - if endof(t) == 1 - rsearch(s, t[1]) - else - _rsearchindex(s, t, sizeof(s)) - end -end - -function rsearchindex(s::String, t::String, i::Integer) - # Check for fast case of a single byte - # (for multi-byte UTF-8 sequences, use rsearchindex instead) - if endof(t) == 1 - rsearch(s, t[1], i) - elseif endof(t) != 0 - j = i ≤ ncodeunits(s) ? nextind(s, i)-1 : i - _rsearchindex(s, t, j) - elseif i > sizeof(s) - return 0 - elseif i == 0 - return 1 - else - return i - end -end - -function _rsearch(s, t, i::Integer) - idx = rsearchindex(s,t,i) - if isempty(t) - idx:idx-1 - else - idx:(idx > 0 ? idx + endof(t) - 1 : -1) - end -end - -rsearch(s::AbstractString, t::AbstractString, i::Integer=endof(s)) = _rsearch(s, t, i) -rsearch(s::ByteArray, t::ByteArray, i::Integer=endof(s)) = _rsearch(s, t, i) +findprev(t::AbstractString, s::AbstractString, i::Integer) = _rsearch(s, t, i) """ - contains(haystack::AbstractString, needle::Union{AbstractString,Char}) + contains(haystack::AbstractString, needle::Union{AbstractString,Regex,Char}) -Determine whether the second argument is a substring of the first. +Determine whether the second argument is a substring of the first. If `needle` +is a regular expression, checks whether `haystack` contains a match. # Examples ```jldoctest julia> contains("JuliaLang is pretty cool!", "Julia") true + +julia> contains("JuliaLang is pretty cool!", 'a') +true + +julia> contains("aba", r"a.a") +true + +julia> contains("abba", r"a.a") +false ``` """ -contains(haystack::AbstractString, needle::Union{AbstractString,Char}) = searchindex(haystack,needle)!=0 +function contains end + +contains(haystack::AbstractString, needle::Union{AbstractString,Char}) = + _searchindex(haystack, needle, start(haystack)) != 0 in(::AbstractString, ::AbstractString) = error("use contains(x,y) for string containment") diff --git a/base/strings/util.jl b/base/strings/util.jl index 522ecf1fd7623..80788e9b07e13 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +const Chars = Union{Char,Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}} + # starts with and ends with predicates """ @@ -258,18 +260,15 @@ function rpad( r == 0 ? string(s, p^q) : string(s, p^q, first(p, r)) end -# splitter can be a Char, Vector{Char}, AbstractString, Regex, ... -# any splitter that provides search(s::AbstractString, splitter) -split(str::T, splitter; limit::Integer=0, keep::Bool=true) where {T<:SubString} = - _split(str, splitter, limit, keep, T[]) - """ split(s::AbstractString, [chars]; limit::Integer=0, keep::Bool=true) Return an array of substrings by splitting the given string on occurrences of the given -character delimiters, which may be specified in any of the formats allowed by `search`'s -second argument (i.e. a single character, collection of characters, string, or regular -expression). If `chars` is omitted, it defaults to the set of all space characters, and +character delimiters, which may be specified in any of the formats allowed by +[`findnext`](@ref)'s first argument (i.e. as a string, regular expression or a function), +or as a single character or collection of characters. + +If `chars` is omitted, it defaults to the set of all space characters, and `keep` is taken to be `false`. The two keyword arguments are optional: they are a maximum size for the result and a flag determining whether empty fields should be kept in the result. @@ -285,12 +284,22 @@ julia> split(a,".") "rch" ``` """ -split(str::T, splitter; limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = - _split(str, splitter, limit, keep, SubString{T}[]) +function split end + +split(str::T, splitter; + limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = + _split(str, splitter, limit, keep, T <: SubString ? T[] : SubString{T}[]) +split(str::T, splitter::Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}; + limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = + _split(str, occursin(splitter), limit, keep, T <: SubString ? T[] : SubString{T}[]) +split(str::T, splitter::Char; + limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = + _split(str, equalto(splitter), limit, keep, T <: SubString ? T[] : SubString{T}[]) + function _split(str::AbstractString, splitter, limit::Integer, keep_empty::Bool, strs::Array) i = start(str) n = endof(str) - r = search(str,splitter,i) + r = findfirst(splitter,str) if r != 0:-1 j, k = first(r), nextind(str,last(r)) while 0 < j <= n && length(strs) != limit-1 @@ -301,7 +310,7 @@ function _split(str::AbstractString, splitter, limit::Integer, keep_empty::Bool, i = k end (k <= j) && (k = nextind(str,j)) - r = search(str,splitter,k) + r = findnext(splitter,str,k) r == 0:-1 && break j, k = first(r), nextind(str,last(r)) end @@ -315,9 +324,6 @@ end # a bit oddball, but standard behavior in Perl, Ruby & Python: split(str::AbstractString) = split(str, _default_delims; limit=0, keep=false) -rsplit(str::T, splitter; limit::Integer=0, keep::Bool=true) where {T<:SubString} = - _rsplit(str, splitter, limit, keep, T[]) - """ rsplit(s::AbstractString, [chars]; limit::Integer=0, keep::Bool=true) @@ -346,12 +352,21 @@ julia> rsplit(a,".";limit=2) "h" ``` """ +function rsplit end + rsplit(str::T, splitter; limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = - _rsplit(str, splitter, limit, keep, SubString{T}[]) + _rsplit(str, splitter, limit, keep, T <: SubString ? T[] : SubString{T}[]) +rsplit(str::T, splitter::Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}; + limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = + _rsplit(str, occursin(splitter), limit, keep, T <: SubString ? T[] : SubString{T}[]) +rsplit(str::T, splitter::Char; + limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = + _rsplit(str, equalto(splitter), limit, keep, T <: SubString ? T[] : SubString{T}[]) + function _rsplit(str::AbstractString, splitter, limit::Integer, keep_empty::Bool, strs::Array) i = start(str) n = endof(str) - r = rsearch(str,splitter) + r = findlast(splitter, str) j = first(r)-1 k = last(r) while((0 <= j < n) && (length(strs) != limit-1)) @@ -360,7 +375,7 @@ function _rsplit(str::AbstractString, splitter, limit::Integer, keep_empty::Bool n = j end (k <= j) && (j = prevind(str,j)) - r = rsearch(str,splitter,j) + r = findprev(splitter,str,j) j = first(r)-1 k = last(r) end @@ -373,6 +388,11 @@ _replace(io, repl, str, r, pattern) = print(io, repl) _replace(io, repl::Function, str, r, pattern) = print(io, repl(SubString(str, first(r), last(r)))) +replace(str::String, pat_repl::Pair{Char}; count::Integer=typemax(Int)) = + replace(str, equalto(first(pat_repl)) => last(pat_repl); count=count) +replace(str::String, pat_repl::Pair{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}}; + count::Integer=typemax(Int)) = + replace(str, occursin(first(pat_repl)) => last(pat_repl), count) function replace(str::String, pat_repl::Pair; count::Integer=typemax(Int)) pattern, repl = pat_repl count == 0 && return str @@ -380,7 +400,7 @@ function replace(str::String, pat_repl::Pair; count::Integer=typemax(Int)) n = 1 e = endof(str) i = a = start(str) - r = search(str,pattern,i) + r = findnext(pattern,str,i) j, k = first(r), last(r) out = IOBuffer(StringVector(floor(Int, 1.2sizeof(str))), true, true) out.size = 0 @@ -397,7 +417,7 @@ function replace(str::String, pat_repl::Pair; count::Integer=typemax(Int)) else i = k = nextind(str, k) end - r = search(str,pattern,k) + r = findnext(pattern,str,k) r == 0:-1 || n == count && break j, k = first(r), last(r) n += 1 @@ -411,8 +431,8 @@ end Search for the given pattern `pat` in `s`, and replace each occurrence with `r`. If `count` is provided, replace at most `count` occurrences. -As with [`search`](@ref), `pat` may be a -single character, a vector or a set of characters, a string, or a regular expression. If `r` +`pat` may be a single character, a vector or a set of characters, a string, +or a regular expression. If `r` is a function, each occurrence is replaced with `r(s)` where `s` is the matched substring. If `pat` is a regular expression and `r` is a `SubstitutionString`, then capture group references in `r` are replaced with the corresponding matched text. diff --git a/base/version.jl b/base/version.jl index 66cc198466d9f..7dc2fe27c3818 100644 --- a/base/version.jl +++ b/base/version.jl @@ -21,7 +21,7 @@ struct VersionNumber if ident isa Integer ident >= 0 || throw(ArgumentError("invalid negative pre-release identifier: $ident")) else - if !ismatch(r"^(?:|[0-9a-z-]*[a-z-][0-9a-z-]*)$"i, ident) || + if !contains(ident, r"^(?:|[0-9a-z-]*[a-z-][0-9a-z-]*)$"i) || isempty(ident) && !(length(pre)==1 && isempty(bld)) throw(ArgumentError("invalid pre-release identifier: $(repr(ident))")) end @@ -31,7 +31,7 @@ struct VersionNumber if ident isa Integer ident >= 0 || throw(ArgumentError("invalid negative build identifier: $ident")) else - if !ismatch(r"^(?:|[0-9a-z-]*[a-z-][0-9a-z-]*)$"i, ident) || + if !contains(ident, r"^(?:|[0-9a-z-]*[a-z-][0-9a-z-]*)$"i) || isempty(ident) && length(bld)!=1 throw(ArgumentError("invalid build identifier: $(repr(ident))")) end @@ -83,7 +83,7 @@ function split_idents(s::AbstractString) idents = split(s, '.') ntuple(length(idents)) do i ident = idents[i] - ismatch(r"^\d+$", ident) ? parse(UInt64, ident) : String(ident) + contains(ident, r"^\d+$") ? parse(UInt64, ident) : String(ident) end end diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index 37e36f548f01b..97991a0681258 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -507,29 +507,30 @@ julia> "1 + 2 = 3" == "1 + 2 = $(1 + 2)" true ``` -You can search for the index of a particular character using the [`search`](@ref) function: +You can search for the index of a particular character using the [`findfirst`](@ref) function: ```jldoctest -julia> search("xylophone", 'x') +julia> findfirst(equalto('x'), "xylophone") 1 -julia> search("xylophone", 'p') +julia> findfirst(equalto('p'), "xylophone") 5 -julia> search("xylophone", 'z') +julia> findfirst(equalto('z'), "xylophone") 0 ``` -You can start the search for a character at a given offset by providing a third argument: +You can start the search for a character at a given offset by using [`findnext`](@ref) +with a third argument: ```jldoctest -julia> search("xylophone", 'o') +julia> findnext(equalto('o'), "xylophone", 1) 4 -julia> search("xylophone", 'o', 5) +julia> findnext(equalto('o'), "xylophone", 5) 7 -julia> search("xylophone", 'o', 8) +julia> findnext(equalto('o'), "xylophone", 8) 0 ``` @@ -603,17 +604,17 @@ julia> typeof(ans) Regex ``` -To check if a regex matches a string, use [`ismatch`](@ref): +To check if a regex matches a string, use [`contains`](@ref): ```jldoctest -julia> ismatch(r"^\s*(?:#|$)", "not a comment") +julia> contains("not a comment", r"^\s*(?:#|$)") false -julia> ismatch(r"^\s*(?:#|$)", "# a comment") +julia> contains("# a comment", r"^\s*(?:#|$)") true ``` -As one can see here, [`ismatch`](@ref) simply returns true or false, indicating whether the +As one can see here, [`contains`](@ref) simply returns true or false, indicating whether the given regex matches the string or not. Commonly, however, one wants to know not just whether a string matched, but also *how* it matched. To capture this information about a match, use the [`match`](@ref) function instead: diff --git a/doc/src/stdlib/collections.md b/doc/src/stdlib/collections.md index 5fccee695aa1a..6c9c33d3a5236 100644 --- a/doc/src/stdlib/collections.md +++ b/doc/src/stdlib/collections.md @@ -77,7 +77,6 @@ Fully implemented by: Base.in Base.eltype Base.indexin -Base.findin Base.unique Base.unique! Base.allunique diff --git a/doc/src/stdlib/strings.md b/doc/src/stdlib/strings.md index 79e2b1b9fb448..1175c11e3268d 100644 --- a/doc/src/stdlib/strings.md +++ b/doc/src/stdlib/strings.md @@ -24,7 +24,6 @@ Base.Docs.@text_str Base.isvalid(::Any) Base.isvalid(::Any, ::Any) Base.isvalid(::AbstractString, ::Integer) -Base.ismatch Base.match Base.eachmatch Base.matchall @@ -33,11 +32,11 @@ Base.:(==)(::AbstractString, ::AbstractString) Base.cmp(::AbstractString, ::AbstractString) Base.lpad Base.rpad -Base.search -Base.rsearch -Base.searchindex -Base.rsearchindex -Base.contains(::AbstractString, ::AbstractString) +Base.findfirst(::AbstractString, ::AbstractString) +Base.findnext(::AbstractString, ::AbstractString, ::Integer) +Base.findlast(::AbstractString, ::AbstractString) +Base.findprev(::AbstractString, ::AbstractString, ::Integer) +Base.contains Base.reverse(::Union{String,SubString{String}}) Base.replace(s::AbstractString, ::Pair) Base.split diff --git a/stdlib/Dates/test/ranges.jl b/stdlib/Dates/test/ranges.jl index 7e9c51cdc0722..2b8d4e03acc84 100644 --- a/stdlib/Dates/test/ranges.jl +++ b/stdlib/Dates/test/ranges.jl @@ -26,7 +26,7 @@ let @test_throws ArgumentError minimum(dr) @test_throws ArgumentError maximum(dr) @test_throws BoundsError dr[1] - @test findin(dr, dr) == Int64[] + @test find(occursin(dr), dr) == Int64[] @test [dr;] == T[] @test isempty(reverse(dr)) @test length(reverse(dr)) == 0 @@ -58,7 +58,7 @@ let if len < 10000 dr1 = [i for i in dr] @test length(dr1) == len - @test findin(dr, dr) == [1:len;] + @test find(occursin(dr), dr) == [1:len;] @test length([dr;]) == len @test dr == dr1 @test hash(dr) == hash(dr1) @@ -84,7 +84,7 @@ let @test_throws ArgumentError minimum(dr) @test_throws ArgumentError maximum(dr) @test_throws BoundsError dr[1] - @test findin(dr, dr) == Int64[] + @test find(occursin(dr), dr) == Int64[] @test [dr;] == T[] @test isempty(reverse(dr)) @test length(reverse(dr)) == 0 @@ -116,7 +116,7 @@ let if len < 10000 dr1 = [i for i in dr] @test length(dr1) == len - @test findin(dr, dr) == [1:len;] + @test find(occursin(dr), dr) == [1:len;] @test length([dr;]) == len @test dr == dr1 @test hash(dr) == hash(dr1) @@ -144,7 +144,7 @@ let @test_throws ArgumentError minimum(dr) @test_throws ArgumentError maximum(dr) @test_throws BoundsError dr[1] - @test findin(dr, dr) == Int64[] + @test find(occursin(dr), dr) == Int64[] @test [dr;] == T[] @test isempty(reverse(dr)) @test length(reverse(dr)) == 0 @@ -176,7 +176,7 @@ let if len < 10000 dr1 = [i for i in dr] @test length(dr1) == len - @test findin(dr, dr) == [1:len;] + @test find(occursin(dr), dr) == [1:len;] @test length([dr;]) == len @test dr == dr1 @test hash(dr) == hash(dr1) @@ -202,7 +202,7 @@ let @test_throws ArgumentError minimum(dr) @test_throws ArgumentError maximum(dr) @test_throws BoundsError dr[1] - @test findin(dr, dr) == Int64[] + @test find(occursin(dr), dr) == Int64[] @test [dr;] == T[] @test isempty(reverse(dr)) @test length(reverse(dr)) == 0 @@ -234,7 +234,7 @@ let if len < 10000 dr1 = [i for i in dr] @test length(dr1) == len - @test findin(dr, dr) == [1:len;] + @test find(occursin(dr), dr) == [1:len;] @test length([dr;]) == len @test dr == dr1 @test hash(dr) == hash(dr1) @@ -293,7 +293,7 @@ drs2 = map(x->Dates.Date(first(x)):step(x):Dates.Date(last(x)), drs) @test map(length, drs) == map(x->size(x)[1], drs) @test map(length, drs) == map(x->length(Dates.Date(first(x)):step(x):Dates.Date(last(x))), drs) @test map(length, drs) == map(x->length(reverse(x)), drs) -@test all(x->findin(x, x)==[1:length(x);], drs[1:4]) +@test all(x->find(occursin(x), x)==[1:length(x);], drs[1:4]) @test isempty(dr2) @test all(x->reverse(x) == range(last(x), -step(x), length(x)), drs) @test all(x->minimum(x) == (step(x) < zero(step(x)) ? last(x) : first(x)), drs[4:end]) @@ -371,7 +371,7 @@ drs = Any[dr, dr1, dr2, dr3, dr4, dr5, dr6, dr7, dr8, dr9, dr10, dr11, dr12, dr13, dr14, dr15, dr16, dr17, dr18, dr19, dr20] @test map(length, drs) == map(x->size(x)[1], drs) -@test all(x->findin(x, x) == [1:length(x);], drs[1:4]) +@test all(x->find(occursin(x), x) == [1:length(x);], drs[1:4]) @test isempty(dr2) @test all(x->reverse(x) == last(x): - step(x):first(x), drs) @test all(x->minimum(x) == (step(x) < zero(step(x)) ? last(x) : first(x)), drs[4:end]) @@ -557,7 +557,7 @@ drs = Any[dr, dr1, dr2, dr3, dr8, dr9, dr10, dr11, dr12, dr13, dr14, dr15, dr16, dr17, dr18, dr19, dr20] @test map(length, drs) == map(x->size(x)[1], drs) -@test all(x->findin(x, x) == [1:length(x);], drs[1:4]) +@test all(x->find(occursin(x), x) == [1:length(x);], drs[1:4]) @test isempty(dr2) @test all(x->reverse(x) == last(x): - step(x):first(x), drs) @test all(x->minimum(x) == (step(x) < zero(step(x)) ? last(x) : first(x)), drs[4:end]) diff --git a/stdlib/Distributed/test/distributed_exec.jl b/stdlib/Distributed/test/distributed_exec.jl index 9f219085b0a54..d4342d1d4336c 100644 --- a/stdlib/Distributed/test/distributed_exec.jl +++ b/stdlib/Distributed/test/distributed_exec.jl @@ -1017,7 +1017,7 @@ if DoFullTest pids=addprocs_with_testenv(4); @test_throws ErrorException rmprocs(pids; waitfor=0.001); # wait for workers to be removed - while any(x -> (x in procs()), pids) + while any(occursin(procs()), pids) sleep(0.1) end end @@ -1482,7 +1482,7 @@ function reuseport_tests() end # Ensure that the code has indeed been successfully executed everywhere - @test all(p -> p in results, procs()) + @test all(occursin(results), procs()) end # Test that the client port is reused. SO_REUSEPORT may not be supported on diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index a7ddfd4cc4daf..3e0fe0d7c5a5d 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -511,10 +511,10 @@ end # Test for warning messages (deprecated) -ismatch_warn(s::AbstractString, output) = contains(output, s) -ismatch_warn(s::Regex, output) = ismatch(s, output) -ismatch_warn(s::Function, output) = s(output) -ismatch_warn(S::Union{AbstractArray,Tuple}, output) = all(s -> ismatch_warn(s, output), S) +contains_warn(output, s::AbstractString) = contains(output, s) +contains_warn(output, s::Regex) = contains(output, s) +contains_warn(output, s::Function) = s(output) +contains_warn(output, S::Union{AbstractArray,Tuple}) = all(s -> contains_warn(output, s), S) """ @test_warn msg expr @@ -536,7 +536,7 @@ macro test_warn(msg, expr) $(esc(expr)) end end - @test ismatch_warn($(esc(msg)), read(fname, String)) + @test contains_warn(read(fname, String), $(esc(msg))) ret finally rm(fname, force=true) diff --git a/stdlib/Test/src/logging.jl b/stdlib/Test/src/logging.jl index 7cc40d1fc8a75..e31b07c448d75 100644 --- a/stdlib/Test/src/logging.jl +++ b/stdlib/Test/src/logging.jl @@ -3,7 +3,7 @@ using Logging import Logging: Info, shouldlog, handle_message, min_enabled_level, catch_exceptions -import Base: ismatch +import Base: contains #------------------------------------------------------------------------------- # Log records @@ -113,7 +113,7 @@ corresponding to the arguments to passed to `AbstractLogger` via the Elements which are present will be matched pairwise with the log record fields using `==` by default, with the special cases that `Symbol`s may be used for the standard log levels, and `Regex`s in the pattern will match string or -Symbol fields using `ismatch`. +Symbol fields using `contains`. # Examples @@ -181,9 +181,9 @@ function match_logs(f, patterns...; match_mode::Symbol=:all, kwargs...) logs,value = collect_test_logs(f; kwargs...) if match_mode == :all didmatch = length(logs) == length(patterns) && - all(ismatch(p,l) for (p,l) in zip(patterns, logs)) + all(contains(l,p) for (p,l) in zip(patterns, logs)) elseif match_mode == :any - didmatch = all(any(ismatch(p,l) for l in logs) for p in patterns) + didmatch = all(any(contains(l,p) for l in logs) for p in patterns) end didmatch,logs,value end @@ -201,15 +201,15 @@ function parse_level(level::Symbol) end end -logfield_ismatch(a, b) = a == b -logfield_ismatch(r::Regex, b) = ismatch(r, b) -logfield_ismatch(r::Regex, b::Symbol) = ismatch(r, String(b)) -logfield_ismatch(a::Symbol, b::LogLevel) = parse_level(a) == b -logfield_ismatch(a::Ignored, b) = true +logfield_contains(a, b) = a == b +logfield_contains(a, r::Regex) = contains(a, r) +logfield_contains(a::Symbol, r::Regex) = contains(String(a), r) +logfield_contains(a::LogLevel, b::Symbol) = a == parse_level(b) +logfield_contains(a, b::Ignored) = true -function ismatch(pattern::Tuple, r::LogRecord) +function contains(r::LogRecord, pattern::Tuple) stdfields = (r.level, r.message, r._module, r.group, r.id, r.file, r.line) - all(logfield_ismatch(p,f) for (p,f) in zip(pattern, stdfields[1:length(pattern)])) + all(logfield_contains(f, p) for (f, p) in zip(stdfields[1:length(pattern)], pattern)) end """ diff --git a/test/arrayops.jl b/test/arrayops.jl index 20ef8b699ccfe..dd75e63b2ee19 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -265,30 +265,30 @@ end a = [3, 5, -7, 6] b = [4, 6, 2, -7, 1] - ind = findin(a, b) + ind = find(occursin(b), a) @test ind == [3,4] - @test findin(a, Int[]) == Int[] - @test findin(Int[], a) == Int[] + @test find(occursin(Int[]), a) == Int[] + @test find(occursin(a), Int[]) == Int[] a = [1,2,3,4,5] b = [2,3,4,6] - @test findin(a, b) == [2,3,4] - @test findin(b, a) == [1,2,3] - @test findin(a, Int[]) == Int[] - @test findin(Int[], a) == Int[] + @test find(occursin(b), a) == [2,3,4] + @test find(occursin(a), b) == [1,2,3] + @test find(occursin(Int[]), a) == Int[] + @test find(occursin(a), Int[]) == Int[] a = collect(1:3:15) b = collect(2:4:10) - @test findin(a, b) == [4] - @test findin([a[1:4]; a[4:end]], b) == [4,5] + @test find(occursin(b), a) == [4] + @test find(occursin(b), [a[1:4]; a[4:end]]) == [4,5] - @test findin([1.0, NaN, 2.0], NaN) == [2] - @test findin([1.0, 2.0, NaN], NaN) == [3] + @test find(occursin(NaN), [1.0, NaN, 2.0]) == [2] + @test find(occursin(NaN), [1.0, 2.0, NaN]) == [3] - @testset "findin for uncomparable element types" begin + @testset "find(::OccursIn, b) for uncomparable element types" begin a = [1 + 1im, 1 - 1im] - @test findin(a, 1 + 1im) == [1] - @test findin(a, a) == [1,2] + @test find(occursin(1 + 1im), a) == [1] + @test find(occursin(a), a) == [1,2] end rt = Base.return_types(setindex!, Tuple{Array{Int32, 3}, UInt8, Vector{Int}, Int16, UnitRange{Int}}) @@ -459,6 +459,10 @@ end @test findprev(equalto(1),a,8) == 6 @test findprev(isodd, [2,4,5,3,9,2,0], 7) == 5 @test findprev(isodd, [2,4,5,3,9,2,0], 2) == 0 + @test findfirst(equalto(0x00), [0x01, 0x00]) == 2 + @test findlast(equalto(0x00), [0x01, 0x00]) == 2 + @test findnext(equalto(0x00), [0x00, 0x01, 0x00], 2) == 3 + @test findprev(equalto(0x00), [0x00, 0x01, 0x00], 2) == 1 end @testset "find with general iterables" begin s = "julia" @@ -1173,7 +1177,7 @@ end # logical indexing a = [1:10;]; acopy = copy(a) - @test deleteat!(a, map(i -> i in idx, 1:length(a))) == [acopy[1:(first(idx)-1)]; acopy[(last(idx)+1):end]] + @test deleteat!(a, map(occursin(idx), 1:length(a))) == [acopy[1:(first(idx)-1)]; acopy[(last(idx)+1):end]] end a = [1:10;] @test deleteat!(a, 11:10) == [1:10;] diff --git a/test/asmvariant.jl b/test/asmvariant.jl index 5c75776bbb6e2..28b0fbd6f124b 100644 --- a/test/asmvariant.jl +++ b/test/asmvariant.jl @@ -4,7 +4,7 @@ using Test ix86 = r"i[356]86" -if Sys.ARCH === :x86_64 || ismatch(ix86, string(Sys.ARCH)) +if Sys.ARCH === :x86_64 || contains(string(Sys.ARCH), ix86) function linear_foo() x = 4 y = 5 @@ -17,16 +17,16 @@ if Sys.ARCH === :x86_64 || ismatch(ix86, string(Sys.ARCH)) code_native(buf,linear_foo,(),:att) output=String(take!(buf)) - @test ismatch(rgx,output) + @test contains(output,rgx) #test that the code output is intel syntax by checking it has no occurrences of '%' code_native(buf,linear_foo,(),:intel) output=String(take!(buf)) - @test !(ismatch(rgx,output)) + @test !contains(output,rgx) code_native(buf,linear_foo,()) output=String(take!(buf)) - @test ismatch(rgx, output) + @test contains(output,rgx) end diff --git a/test/bitset.jl b/test/bitset.jl index b30e19b242e49..c6ab52adc52c1 100644 --- a/test/bitset.jl +++ b/test/bitset.jl @@ -6,7 +6,7 @@ data_in = (1,5,100) s = BitSet(data_in) data_out = collect(s) - @test all(map(d->in(d,data_out), data_in)) + @test all(map(occursin(data_out), data_in)) @test length(data_out) === length(data_in) end diff --git a/test/choosetests.jl b/test/choosetests.jl index 5989e266bbde5..21b8585bcbbd2 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -150,7 +150,7 @@ function choosetests(choices = []) end if !net_on - filter!(x -> !(x in net_required_for), tests) + filter!(!occursin(net_required_for), tests) end if "stdlib" in skip_tests @@ -178,7 +178,7 @@ function choosetests(choices = []) # The shift and invert solvers need SuiteSparse for sparse input Base.USE_GPL_LIBS || filter!(x->x != "IterativeEigensolvers", STDLIBS) - filter!(x -> !(x in skip_tests), tests) + filter!(!occursin(skip_tests), tests) tests, net_on, exit_on_error, seed end diff --git a/test/compile.jl b/test/compile.jl index a086045c1cf9e..2fc3702c2885e 100644 --- a/test/compile.jl +++ b/test/compile.jl @@ -274,7 +274,7 @@ try error("__precompile__ disabled test failed") catch exc isa(exc, ErrorException) || rethrow(exc) - !isempty(search(exc.msg, "__precompile__(false)")) && rethrow(exc) + contains(exc.msg, "__precompile__(false)") && rethrow(exc) end # Issue #12720 @@ -341,7 +341,7 @@ try error("\"LoadError: break me\" test failed") catch exc isa(exc, ErrorException) || rethrow(exc) - !isempty(search(exc.msg, "ERROR: LoadError: break me")) && rethrow(exc) + contains(exc.msg, "ERROR: LoadError: break me") && rethrow(exc) end # Test transitive dependency for #21266 @@ -458,7 +458,7 @@ let dir = mktempdir() let fname = tempname() try @test readchomp(pipeline(`$exename -E $(testcode)`, stderr=fname)) == "nothing" - @test ismatch(Regex("Replacing module `$Test_module`"), read(fname, String)) + @test contains(read(fname, String), Regex("Replacing module `$Test_module`")) finally rm(fname, force=true) end @@ -470,7 +470,7 @@ let dir = mktempdir() try @test readchomp(pipeline(`$exename -E $(testcode)`, stderr=fname)) == "nothing" # e.g `@test_nowarn` - @test Test.ismatch_warn(r"^(?!.)"s, read(fname, String)) + @test Test.contains_warn(read(fname, String), r"^(?!.)"s) finally rm(fname, force=true) end diff --git a/test/goto.jl b/test/goto.jl index 11f1a9f024958..4e8063ffb0990 100644 --- a/test/goto.jl +++ b/test/goto.jl @@ -75,7 +75,7 @@ let e = Meta.lower(@__MODULE__, quote end end) @test (e::Expr).head === :error - @test ismatch(r"label \"#\d+#a\" referenced but not defined", e.args[1]) + @test contains(e.args[1], r"label \"#\d+#a\" referenced but not defined") end function goto_test5_3() diff --git a/test/libdl.jl b/test/libdl.jl index 1cc1b19dd351b..af2b396b92421 100644 --- a/test/libdl.jl +++ b/test/libdl.jl @@ -13,7 +13,7 @@ if !Sys.iswindows() || Sys.windows_version() >= Sys.WINDOWS_VISTA_VER end end @test length(filter(dlls) do dl - return ismatch(Regex("^libjulia(?:.*)\\.$(Libdl.dlext)(?:\\..+)?\$"), basename(dl)) + return contains(basename(dl), Regex("^libjulia(?:.*)\\.$(Libdl.dlext)(?:\\..+)?\$")) end) == 1 # look for something libjulia-like (but only one) # library handle pointer must not be NULL diff --git a/test/logging.jl b/test/logging.jl index 39bcc9ec73b07..eb73c3180ddee 100644 --- a/test/logging.jl +++ b/test/logging.jl @@ -59,7 +59,7 @@ end @test record.file == Base.source_path() @test record.line == kwargs[:real_line] @test record.id isa Symbol - @test ismatch(r"^.*logging_[[:xdigit:]]{8}$", String(record.id)) + @test contains(String(record.id), r"^.*logging_[[:xdigit:]]{8}$") # User-defined metadata @test kwargs[:bar_val] === bar_val @@ -69,13 +69,13 @@ end # Keyword values accessible from message block record2 = logs[2] - @test ismatch((Info,"test2"), record2) + @test contains(record2, (Info,"test2")) kwargs = record2.kwargs @test kwargs[:value_in_msg_block] === 1000.0 # Splatting of keywords record3 = logs[3] - @test ismatch((Info,"test3"), record3) + @test contains(record3, (Info,"test3")) kwargs = record3.kwargs @test sort(collect(keys(kwargs))) == [:a, :b] @test kwargs[:a] === 1 diff --git a/test/pkg.jl b/test/pkg.jl index b2aa9ae5e801b..3f2dee5d118b2 100644 --- a/test/pkg.jl +++ b/test/pkg.jl @@ -516,9 +516,9 @@ temp_pkg_dir() do logs,_ = Test.collect_test_logs() do Pkg.update("ColorTypes") end - @test any(ismatch((:info,r"Upgrading ColorTypes: v0\.2\.2 => v\d+\.\d+\.\d+"), l) for l in logs) - @test any(ismatch((:info,r"Upgrading Compat: v0\.7\.18 => v\d+\.\d+\.\d+"), l) for l in logs) - @test !any(ismatch((:info,r"Upgrading Colors"),l) for l in logs) + @test any(contains(l, (:info,r"Upgrading ColorTypes: v0\.2\.2 => v\d+\.\d+\.\d+")) for l in logs) + @test any(contains(l, (:info,r"Upgrading Compat: v0\.7\.18 => v\d+\.\d+\.\d+")) for l in logs) + @test !any(contains(l, (:info,r"Upgrading Colors")) for l in logs) @test Pkg.installed("Colors") == v"0.6.4" @@ -541,7 +541,7 @@ temp_pkg_dir() do Pkg.add(package) msg = read(ignorestatus(`$(Base.julia_cmd()) --startup-file=no -e "redirect_stderr(STDOUT); using Logging; global_logger(SimpleLogger(STDOUT)); using Example; Pkg.update(\"$package\")"`), String) - @test ismatch(Regex("- $package.*Restart Julia to use the updated versions","s"), msg) + @test contains(msg, Regex("- $package.*Restart Julia to use the updated versions","s")) end # Verify that the --startup-file flag is respected by Pkg.build / Pkg.test diff --git a/test/ranges.jl b/test/ranges.jl index bb93377e35c48..2eaf006018891 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -249,21 +249,15 @@ end @test length(0.0:-0.5) == 0 @test length(1:2:0) == 0 end - @testset "findin" begin - @test findin([5.2, 3.3], 3:20) == findin([5.2, 3.3], collect(3:20)) + @testset "find(::OccursIn, ::Array)" begin + @test find(occursin(3:20), [5.2, 3.3]) == find(occursin(collect(3:20)), [5.2, 3.3]) let span = 5:20, r = -7:3:42 - @test findin(r, span) == 5:10 + @test find(occursin(span), r) == 5:10 r = 15:-2:-38 - @test findin(r, span) == 1:6 + @test find(occursin(span), r) == 1:6 end - #@test isempty(findin(5+0*(1:6), 2:4)) - #@test findin(5+0*(1:6), 2:5) == 1:6 - #@test findin(5+0*(1:6), 2:7) == 1:6 - #@test findin(5+0*(1:6), 5:7) == 1:6 - #@test isempty(findin(5+0*(1:6), 6:7)) - #@test findin(5+0*(1:6), 5:5) == 1:6 end @testset "reverse" begin @test reverse(reverse(1:10)) == 1:10 @@ -1115,15 +1109,16 @@ end @test intersect(r, Base.OneTo(2)) == Base.OneTo(2) @test intersect(r, 0:5) == 1:3 @test intersect(r, 2) === intersect(2, r) === 2:2 - @test findin(r, r) === findin(r, 1:length(r)) === findin(1:length(r), r) === 1:length(r) + @test find(occursin(r), r) === find(occursin(1:length(r)), r) === + find(occursin(r), 1:length(r)) === 1:length(r) io = IOBuffer() show(io, r) str = String(take!(io)) @test str == "Base.OneTo(3)" end let r = Base.OneTo(7) - @test findin(r, 2:(length(r) - 1)) === 2:(length(r) - 1) - @test findin(2:(length(r) - 1), r) === 1:(length(r) - 2) + @test find(occursin(2:(length(r) - 1)), r) === 2:(length(r) - 1) + @test find(occursin(r), 2:(length(r) - 1)) === 1:(length(r) - 2) end end diff --git a/test/reflection.jl b/test/reflection.jl index 22fdd10ced013..b5dfd45d87155 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -27,8 +27,8 @@ function test_code_reflection(freflect, f, types, tester) end function test_code_reflections(tester, freflect) - test_code_reflection(freflect, ismatch, - Tuple{Regex, AbstractString}, tester) # abstract type + test_code_reflection(freflect, contains, + Tuple{AbstractString, Regex}, tester) # abstract type test_code_reflection(freflect, +, Tuple{Int, Int}, tester) # leaftype signature test_code_reflection(freflect, +, Tuple{Array{Float32}, Array{Float32}}, tester) # incomplete types @@ -61,7 +61,7 @@ function warntype_hastag(f, types, tag) iob = IOBuffer() code_warntype(iob, f, types) str = String(take!(iob)) - return !isempty(search(str, tag)) + return contains(str, tag) end pos_stable(x) = x > 0 ? x : zero(x) @@ -90,7 +90,7 @@ tag = "ANY" iob = IOBuffer() show(iob, Meta.lower(Main, :(x -> x^2))) str = String(take!(iob)) -@test isempty(search(str, tag)) +@test !contains(str, tag) # Make sure non used variables are not emphasized has_unused() = (a = rand(5)) @@ -475,12 +475,12 @@ function test_typed_ast_printing(Base.@nospecialize(f), Base.@nospecialize(types for i in 1:length(src.slotnames) name = src.slotnames[i] if name in dupnames - if name in must_used_vars && ismatch(Regex("_$i\\b"), str) + if name in must_used_vars && contains(str, Regex("_$i\\b")) must_used_checked[name] = true global used_dup_var_tested15714 = true end else - @test !ismatch(Regex("_$i\\b"), str) + @test !contains(str, Regex("_$i\\b")) if name in must_used_vars global used_unique_var_tested15714 = true end @@ -499,7 +499,7 @@ function test_typed_ast_printing(Base.@nospecialize(f), Base.@nospecialize(types # Use the variable names that we know should be present in the optimized AST for i in 2:length(src.slotnames) name = src.slotnames[i] - if name in must_used_vars && ismatch(Regex("_$i\\b"), str) + if name in must_used_vars && contains(str, Regex("_$i\\b")) must_used_checked[name] = true end end diff --git a/test/regex.jl b/test/regex.jl index 742d4fc8dabb5..4acd9c9269482 100644 --- a/test/regex.jl +++ b/test/regex.jl @@ -32,11 +32,11 @@ show(buf, r"") @test read(buf, String) == "r\"\"" # see #10994, #11447: PCRE2 allows NUL chars in the pattern -@test ismatch(Regex("^a\0b\$"), "a\0b") +@test contains("a\0b", Regex("^a\0b\$")) # regex match / search string must be a String @test_throws ArgumentError match(r"test", GenericString("this is a test")) -@test_throws ArgumentError search(GenericString("this is a test"), r"test") +@test_throws ArgumentError findfirst(r"test", GenericString("this is a test")) # Named subpatterns let m = match(r"(?<a>.)(.)(?<b>.)", "xyz") diff --git a/test/repl.jl b/test/repl.jl index 7317a01353c3b..e0aa274cf46c1 100644 --- a/test/repl.jl +++ b/test/repl.jl @@ -195,10 +195,10 @@ fake_repl() do stdin_write, stdout_read, repl # Issue #10222 # Test ignoring insert key in standard and prefix search modes write(stdin_write, "\e[2h\e[2h\n") # insert (VT100-style) - @test search(readline(stdout_read), "[2h") == 0:-1 + @test findfirst("[2h", readline(stdout_read)) == 0:-1 readline(stdout_read) write(stdin_write, "\e[2~\e[2~\n") # insert (VT220-style) - @test search(readline(stdout_read), "[2~") == 0:-1 + @test findfirst("[2~", readline(stdout_read)) == 0:-1 readline(stdout_read) write(stdin_write, "1+1\n") # populate history with a trivial input readline(stdout_read) @@ -818,27 +818,28 @@ for keys = [altkeys, merge(altkeys...)], # Check that the correct prompt was displayed output = readuntil(stdout_read, "1 * 1;") - @test !isempty(search(output, LineEdit.prompt_string(altprompt))) - @test isempty(search(output, "julia> ")) + @test !contains(LineEdit.prompt_string(altprompt), output) + @test !contains("julia> ", output) # Check the history file history = read(histfile, String) - @test ismatch(r""" - ^\#\ time:\ .*\n - \#\ mode:\ julia\n - \t1\ \+\ 1;\n - \#\ time:\ .*\n - \#\ mode:\ julia\n - \tmulti=2;\n - \tline=2;\n - \#\ time:\ .*\n - \#\ mode:\ julia\n - \tmulti=3;\n - \tline=1;\n - \#\ time:\ .*\n - \#\ mode:\ julia\n - \t1\ \*\ 1;\n$ - """xm, history) + @test contains(history, + r""" + ^\#\ time:\ .*\n + \#\ mode:\ julia\n + \t1\ \+\ 1;\n + \#\ time:\ .*\n + \#\ mode:\ julia\n + \tmulti=2;\n + \tline=2;\n + \#\ time:\ .*\n + \#\ mode:\ julia\n + \tmulti=3;\n + \tline=1;\n + \#\ time:\ .*\n + \#\ mode:\ julia\n + \t1\ \*\ 1;\n$ + """xm) end finally rm(histfile, force=true) diff --git a/test/replutil.jl b/test/replutil.jl index 9d5b15f3df69d..38d2f76d0dffd 100644 --- a/test/replutil.jl +++ b/test/replutil.jl @@ -310,7 +310,7 @@ let err_str, @test contains(err_str, "MethodError: objects of type Array{Float64,1} are not callable") end @test stringmime("text/plain", FunctionLike()) == "(::$(curmod_prefix)FunctionLike) (generic function with 0 methods)" -@test ismatch(r"^@doc \(macro with \d+ method[s]?\)$", stringmime("text/plain", getfield(Base, Symbol("@doc")))) +@test contains(stringmime("text/plain", getfield(Base, Symbol("@doc"))), r"^@doc \(macro with \d+ method[s]?\)$") method_defs_lineno = @__LINE__() + 1 Base.Symbol() = throw(ErrorException("1")) diff --git a/test/serialize.jl b/test/serialize.jl index 2f68f74fd9dbb..e35720f2982f1 100644 --- a/test/serialize.jl +++ b/test/serialize.jl @@ -441,8 +441,8 @@ using .Shell, .Instance1 io = IOBuffer() serialize(io, foo) str = String(take!(io)) -@test isempty(search(str, "Instance1")) -@test !isempty(search(str, "Shell")) +@test !contains(str, "Instance1") +@test contains(str, "Shell") end # module Test13452 diff --git a/test/sets.jl b/test/sets.jl index 1d802e0b63f62..dd9f10a7cd9a2 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -11,7 +11,7 @@ using Main.TestHelpers.OAs s = Set(data_in) data_out = collect(s) @test ===(typeof(data_out), Array{Any,1}) - @test all(map(d->in(d,data_out), data_in)) + @test all(map(occursin(data_out), data_in)) @test length(data_out) == length(data_in) let f17741 = x -> x < 0 ? false : 1 @test isa(Set(x for x = 1:3), Set{Int}) diff --git a/test/show.jl b/test/show.jl index 333bf65136a55..996ba7dde847c 100644 --- a/test/show.jl +++ b/test/show.jl @@ -408,7 +408,7 @@ let a = Expr(:quote,Expr(:$,:x8d003)) end # issue #9865 -@test ismatch(r"^Set\(\[.+….+\]\)$", replstr(Set(1:100))) +@test contains(replstr(Set(1:100)), r"^Set\(\[.+….+\]\)$") # issue #11413 @test string(:(*{1, 2})) == "*{1, 2}" @@ -752,7 +752,7 @@ let repr = sprint(dump, Int64) end let repr = sprint(dump, Any) @test length(repr) == 4 - @test ismatch(r"^Any\n", repr) + @test contains(repr, r"^Any\n") @test endswith(repr, '\n') end let repr = sprint(dump, Integer) diff --git a/test/spawn.jl b/test/spawn.jl index 90d9cc66a3566..dd33d032a7309 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -46,8 +46,8 @@ end @test length(spawn(pipeline(`$echocmd hello`, sortcmd)).processes) == 2 out = read(`$echocmd hello` & `$echocmd world`, String) -@test search(out,"world") != 0:-1 -@test search(out,"hello") != 0:-1 +@test contains(out,"world") +@test contains(out,"hello") @test read(pipeline(`$echocmd hello` & `$echocmd world`, sortcmd), String) == "hello\nworld\n" @test (run(`$printfcmd " \033[34m[stdio passthrough ok]\033[0m\n"`); true) diff --git a/test/strings/search.jl b/test/strings/search.jl index c609066c4f05c..8d499207589eb 100644 --- a/test/strings/search.jl +++ b/test/strings/search.jl @@ -7,377 +7,316 @@ u8str = "∀ ε > 0, ∃ δ > 0: |x-y| < δ ⇒ |f(x)-f(y)| < ε" # I think these should give error on 4 also, and "" is not treated # consistently with SubString("",1,1), nor with Char[] for ind in (0, 5) - @test_throws BoundsError search("foo", SubString("",1,1), ind) - @test_throws BoundsError rsearch("foo", SubString("",1,1), ind) - @test_throws BoundsError searchindex("foo", SubString("",1,1), ind) - @test_throws BoundsError rsearchindex("foo", SubString("",1,1), ind) + @test_throws BoundsError findnext(SubString("",1,1), "foo", ind) + @test_throws BoundsError findprev(SubString("",1,1), "foo", ind) end -# Note: the commented out tests will be enabled after fixes to make -# sure that search/rsearch/searchindex/rsearchindex are consistent +# Note: the commented out test will be enabled after fixes to make +# sure that findnext/findprev are consistent # no matter what type of AbstractString the second argument is -@test_throws BoundsError search("foo", Char[], 0) -@test_throws BoundsError search("foo", Char[], 5) -# @test_throws BoundsError rsearch("foo", Char[], 0) -@test_throws BoundsError rsearch("foo", Char[], 5) - -# @test_throws BoundsError searchindex("foo", Char[], 0) -# @test_throws BoundsError searchindex("foo", Char[], 5) -# @test_throws BoundsError rsearchindex("foo", Char[], 0) -# @test_throws BoundsError rsearchindex("foo", Char[], 5) +@test_throws BoundsError findnext(equalto('a'), "foo", 0) +@test_throws BoundsError findnext(occursin(Char[]), "foo", 5) +# @test_throws BoundsError findprev(occursin(Char[]), "foo", 0) +@test_throws BoundsError findprev(occursin(Char[]), "foo", 5) # @test_throws ErrorException in("foobar","bar") -@test_throws BoundsError search(b"\x1\x2",0x1,0) -@test rsearchindex(b"foo",b"o",0) == 0 -@test rsearchindex(SubString("",1,0),SubString("",1,0)) == 1 - -@test search(b"foo",'o') == 2 -@test rsearch(b"foo",'o') == 3 -@test search(b"foó",'ó') == 3 -@test rsearch(b"foó",'ó') == 3 +@test_throws BoundsError findnext(equalto(0x1),b"\x1\x2",0) -# ascii search +# ascii forward search for str in [astr, GenericString(astr)] - @test_throws BoundsError search(str, 'z', 0) - @test_throws BoundsError search(str, '∀', 0) - @test search(str, 'x') == 0 - @test search(str, '\0') == 0 - @test search(str, '\u80') == 0 - @test search(str, '∀') == 0 - @test search(str, 'H') == 1 - @test search(str, 'l') == 3 - @test search(str, 'l', 4) == 4 - @test search(str, 'l', 5) == 11 - @test search(str, 'l', 12) == 0 - @test search(str, ',') == 6 - @test search(str, ',', 7) == 0 - @test search(str, '\n') == 14 - @test search(str, '\n', 15) == 0 - @test_throws BoundsError search(str, 'ε', nextind(str,endof(str))+1) - @test_throws BoundsError search(str, 'a', nextind(str,endof(str))+1) + @test_throws BoundsError findnext(equalto('z'), str, 0) + @test_throws BoundsError findnext(equalto('∀'), str, 0) + @test findfirst(equalto('x'), str) == 0 + @test findfirst(equalto('\0'), str) == 0 + @test findfirst(equalto('\u80'), str) == 0 + @test findfirst(equalto('∀'), str) == 0 + @test findfirst(equalto('H'), str) == 1 + @test findfirst(equalto('l'), str) == 3 + @test findnext(equalto('l'), str, 4) == 4 + @test findnext(equalto('l'), str, 5) == 11 + @test findnext(equalto('l'), str, 12) == 0 + @test findfirst(equalto(','), str) == 6 + @test findnext(equalto(','), str, 7) == 0 + @test findfirst(equalto('\n'), str) == 14 + @test findnext(equalto('\n'), str, 15) == 0 + @test_throws BoundsError findnext(equalto('ε'), str, nextind(str,endof(str))+1) + @test_throws BoundsError findnext(equalto('a'), str, nextind(str,endof(str))+1) end -# ascii rsearch +# ascii backward search for str in [astr] - @test rsearch(str, 'x') == 0 - @test rsearch(str, '\0') == 0 - @test rsearch(str, '\u80') == 0 - @test rsearch(str, '∀') == 0 - @test rsearch(str, 'H') == 1 - @test rsearch(str, 'H', 0) == 0 - @test rsearch(str, 'l') == 11 - @test rsearch(str, 'l', 5) == 4 - @test rsearch(str, 'l', 4) == 4 - @test rsearch(str, 'l', 3) == 3 - @test rsearch(str, 'l', 2) == 0 - @test rsearch(str, ',') == 6 - @test rsearch(str, ',', 5) == 0 - @test rsearch(str, '\n') == 14 + @test findlast(equalto('x'), str) == 0 + @test findlast(equalto('\0'), str) == 0 + @test findlast(equalto('\u80'), str) == 0 + @test findlast(equalto('∀'), str) == 0 + @test findlast(equalto('H'), str) == 1 + @test findprev(equalto('H'), str, 0) == 0 + @test findlast(equalto('l'), str) == 11 + @test findprev(equalto('l'), str, 5) == 4 + @test findprev(equalto('l'), str, 4) == 4 + @test findprev(equalto('l'), str, 3) == 3 + @test findprev(equalto('l'), str, 2) == 0 + @test findlast(equalto(','), str) == 6 + @test findprev(equalto(','), str, 5) == 0 + @test findlast(equalto('\n'), str) == 14 end -# utf-8 search +# utf-8 forward search for str in (u8str, GenericString(u8str)) - @test_throws BoundsError search(str, 'z', 0) - @test_throws BoundsError search(str, '∀', 0) - @test search(str, 'z') == 0 - @test search(str, '\0') == 0 - @test search(str, '\u80') == 0 - @test search(str, '∄') == 0 - @test search(str, '∀') == 1 - @test_throws StringIndexError search(str, '∀', 2) - @test search(str, '∀', 4) == 0 - @test search(str, '∃') == 13 - @test_throws StringIndexError search(str, '∃', 15) - @test search(str, '∃', 16) == 0 - @test search(str, 'x') == 26 - @test search(str, 'x', 27) == 43 - @test search(str, 'x', 44) == 0 - @test search(str, 'δ') == 17 - @test_throws StringIndexError search(str, 'δ', 18) - @test search(str, 'δ', nextind(str,17)) == 33 - @test search(str, 'δ', nextind(str,33)) == 0 - @test search(str, 'ε') == 5 - @test search(str, 'ε', nextind(str,5)) == 54 - @test search(str, 'ε', nextind(str,54)) == 0 - @test search(str, 'ε', nextind(str,endof(str))) == 0 - @test search(str, 'a', nextind(str,endof(str))) == 0 - @test_throws BoundsError search(str, 'ε', nextind(str,endof(str))+1) - @test_throws BoundsError search(str, 'a', nextind(str,endof(str))+1) + @test_throws BoundsError findnext(equalto('z'), str, 0) + @test_throws BoundsError findnext(equalto('∀'), str, 0) + @test findfirst(equalto('z'), str) == 0 + @test findfirst(equalto('\0'), str) == 0 + @test findfirst(equalto('\u80'), str) == 0 + @test findfirst(equalto('∄'), str) == 0 + @test findfirst(equalto('∀'), str) == 1 + @test_throws StringIndexError findnext(equalto('∀'), str, 2) + @test findnext(equalto('∀'), str, 4) == 0 + @test findfirst(equalto('∃'), str) == 13 + @test_throws StringIndexError findnext(equalto('∃'), str, 15) + @test findnext(equalto('∃'), str, 16) == 0 + @test findfirst(equalto('x'), str) == 26 + @test findnext(equalto('x'), str, 27) == 43 + @test findnext(equalto('x'), str, 44) == 0 + @test findfirst(equalto('δ'), str) == 17 + @test_throws StringIndexError findnext(equalto('δ'), str, 18) + @test findnext(equalto('δ'), str, nextind(str,17)) == 33 + @test findnext(equalto('δ'), str, nextind(str,33)) == 0 + @test findfirst(equalto('ε'), str) == 5 + @test findnext(equalto('ε'), str, nextind(str,5)) == 54 + @test findnext(equalto('ε'), str, nextind(str,54)) == 0 + @test findnext(equalto('ε'), str, nextind(str,endof(str))) == 0 + @test findnext(equalto('a'), str, nextind(str,endof(str))) == 0 + @test_throws BoundsError findnext(equalto('ε'), str, nextind(str,endof(str))+1) + @test_throws BoundsError findnext(equalto('a'), str, nextind(str,endof(str))+1) end -# utf-8 rsearch +# utf-8 backward search for str in [u8str] - @test rsearch(str, 'z') == 0 - @test rsearch(str, '\0') == 0 - @test rsearch(str, '\u80') == 0 - @test rsearch(str, '∄') == 0 - @test rsearch(str, '∀') == 1 - @test rsearch(str, '∀', 0) == 0 - @test rsearch(str, '∃') == 13 - @test rsearch(str, '∃', 14) == 13 - @test rsearch(str, '∃', 13) == 13 - @test rsearch(str, '∃', 12) == 0 - @test rsearch(str, 'x') == 43 - @test rsearch(str, 'x', 42) == 26 - @test rsearch(str, 'x', 25) == 0 - @test rsearch(str, 'δ') == 33 - @test rsearch(str, 'δ', 32) == 17 - @test rsearch(str, 'δ', 16) == 0 - @test rsearch(str, 'ε') == 54 - @test rsearch(str, 'ε', 53) == 5 - @test rsearch(str, 'ε', 4) == 0 + @test findlast(equalto('z'), str) == 0 + @test findlast(equalto('\0'), str) == 0 + @test findlast(equalto('\u80'), str) == 0 + @test findlast(equalto('∄'), str) == 0 + @test findlast(equalto('∀'), str) == 1 + @test findprev(equalto('∀'), str, 0) == 0 + @test findlast(equalto('∃'), str) == 13 + @test findprev(equalto('∃'), str, 14) == 13 + @test findprev(equalto('∃'), str, 13) == 13 + @test findprev(equalto('∃'), str, 12) == 0 + @test findlast(equalto('x'), str) == 43 + @test findprev(equalto('x'), str, 42) == 26 + @test findprev(equalto('x'), str, 25) == 0 + @test findlast(equalto('δ'), str) == 33 + @test findprev(equalto('δ'), str, 32) == 17 + @test findprev(equalto('δ'), str, 16) == 0 + @test findlast(equalto('ε'), str) == 54 + @test findprev(equalto('ε'), str, 53) == 5 + @test findprev(equalto('ε'), str, 4) == 0 end -# string search with a single-char string -@test search(astr, "x") == 0:-1 -@test search(astr, "H") == 1:1 -@test search(astr, "H", 2) == 0:-1 -@test search(astr, "l") == 3:3 -@test search(astr, "l", 4) == 4:4 -@test search(astr, "l", 5) == 11:11 -@test search(astr, "l", 12) == 0:-1 -@test search(astr, "\n") == 14:14 -@test search(astr, "\n", 15) == 0:-1 - -@test search(u8str, "z") == 0:-1 -@test search(u8str, "∄") == 0:-1 -@test search(u8str, "∀") == 1:1 -@test search(u8str, "∀", 4) == 0:-1 -@test search(u8str, "∃") == 13:13 -@test search(u8str, "∃", 16) == 0:-1 -@test search(u8str, "x") == 26:26 -@test search(u8str, "x", 27) == 43:43 -@test search(u8str, "x", 44) == 0:-1 -@test search(u8str, "ε") == 5:5 -@test search(u8str, "ε", 7) == 54:54 -@test search(u8str, "ε", 56) == 0:-1 - -# string rsearch with a single-char string -@test rsearch(astr, "x") == 0:-1 -@test rsearch(astr, "H") == 1:1 -@test rsearch(astr, "H", 2) == 1:1 -@test rsearch(astr, "H", 0) == 0:-1 -@test rsearch(astr, "l") == 11:11 -@test rsearch(astr, "l", 10) == 4:4 -@test rsearch(astr, "l", 4) == 4:4 -@test rsearch(astr, "l", 3) == 3:3 -@test rsearch(astr, "l", 2) == 0:-1 -@test rsearch(astr, "\n") == 14:14 -@test rsearch(astr, "\n", 13) == 0:-1 - -@test rsearch(u8str, "z") == 0:-1 -@test rsearch(u8str, "∄") == 0:-1 -@test rsearch(u8str, "∀") == 1:1 -@test rsearch(u8str, "∀", 0) == 0:-1 +# string forward search with a single-char string +@test findfirst("x", astr) == 0:-1 +@test findfirst("H", astr) == 1:1 +@test findnext("H", astr, 2) == 0:-1 +@test findfirst("l", astr) == 3:3 +@test findnext("l", astr, 4) == 4:4 +@test findnext("l", astr, 5) == 11:11 +@test findnext("l", astr, 12) == 0:-1 +@test findfirst("\n", astr) == 14:14 +@test findnext("\n", astr, 15) == 0:-1 + +@test findfirst("z", u8str) == 0:-1 +@test findfirst("∄", u8str) == 0:-1 +@test findfirst("∀", u8str) == 1:1 +@test findnext("∀", u8str, 4) == 0:-1 +@test findfirst("∃", u8str) == 13:13 +@test findnext("∃", u8str, 16) == 0:-1 +@test findfirst("x", u8str) == 26:26 +@test findnext("x", u8str, 27) == 43:43 +@test findnext("x", u8str, 44) == 0:-1 +@test findfirst("ε", u8str) == 5:5 +@test findnext("ε", u8str, 7) == 54:54 +@test findnext("ε", u8str, 56) == 0:-1 + +# strifindprev backward search with a single-char string +@test findlast("x", astr) == 0:-1 +@test findlast("H", astr) == 1:1 +@test findprev("H", astr, 2) == 1:1 +@test findprev("H", astr, 0) == 0:-1 +@test findlast("l", astr) == 11:11 +@test findprev("l", astr, 10) == 4:4 +@test findprev("l", astr, 4) == 4:4 +@test findprev("l", astr, 3) == 3:3 +@test findprev("l", astr, 2) == 0:-1 +@test findlast("\n", astr) == 14:14 +@test findprev("\n", astr, 13) == 0:-1 + +@test findlast("z", u8str) == 0:-1 +@test findlast("∄", u8str) == 0:-1 +@test findlast("∀", u8str) == 1:1 +@test findprev("∀", u8str, 0) == 0:-1 #TODO: setting the limit in the middle of a wide char -# makes search fail but rsearch succeed. -# Should rsearch fail as well? -#@test rsearch(u8str, "∀", 2) == 0:-1 # gives 1:3 -@test rsearch(u8str, "∃") == 13:13 -@test rsearch(u8str, "∃", 12) == 0:-1 -@test rsearch(u8str, "x") == 43:43 -@test rsearch(u8str, "x", 42) == 26:26 -@test rsearch(u8str, "x", 25) == 0:-1 -@test rsearch(u8str, "ε") == 54:54 -@test rsearch(u8str, "ε", 53) == 5:5 -@test rsearch(u8str, "ε", 4) == 0:-1 - -# string search with a single-char regex -@test search(astr, r"x") == 0:-1 -@test search(astr, r"H") == 1:1 -@test search(astr, r"H", 2) == 0:-1 -@test search(astr, r"l") == 3:3 -@test search(astr, r"l", 4) == 4:4 -@test search(astr, r"l", 5) == 11:11 -@test search(astr, r"l", 12) == 0:-1 -@test search(astr, r"\n") == 14:14 -@test search(astr, r"\n", 15) == 0:-1 -@test search(u8str, r"z") == 0:-1 -@test search(u8str, r"∄") == 0:-1 -@test search(u8str, r"∀") == 1:1 -@test search(u8str, r"∀", 4) == 0:-1 -@test search(u8str, r"∀") == search(u8str, r"\u2200") -@test search(u8str, r"∀", 4) == search(u8str, r"\u2200", 4) -@test search(u8str, r"∃") == 13:13 -@test search(u8str, r"∃", 16) == 0:-1 -@test search(u8str, r"x") == 26:26 -@test search(u8str, r"x", 27) == 43:43 -@test search(u8str, r"x", 44) == 0:-1 -@test search(u8str, r"ε") == 5:5 -@test search(u8str, r"ε", 7) == 54:54 -@test search(u8str, r"ε", 56) == 0:-1 +# makes findnext fail but findprev succeed. +# Should findprev fail as well? +#@test findprev("∀", u8str, 2) == 0:-1 # gives 1:3 +@test findlast("∃", u8str) == 13:13 +@test findprev("∃", u8str, 12) == 0:-1 +@test findlast("x", u8str) == 43:43 +@test findprev("x", u8str, 42) == 26:26 +@test findprev("x", u8str, 25) == 0:-1 +@test findlast("ε", u8str) == 54:54 +@test findprev("ε", u8str, 53) == 5:5 +@test findprev("ε", u8str, 4) == 0:-1 + +# string forward search with a single-char regex +@test findfirst(r"x", astr) == 0:-1 +@test findfirst(r"H", astr) == 1:1 +@test findnext(r"H", astr, 2) == 0:-1 +@test findfirst(r"l", astr) == 3:3 +@test findnext(r"l", astr, 4) == 4:4 +@test findnext(r"l", astr, 5) == 11:11 +@test findnext(r"l", astr, 12) == 0:-1 +@test findfirst(r"\n", astr) == 14:14 +@test findnext(r"\n", astr, 15) == 0:-1 +@test findfirst(r"z", u8str) == 0:-1 +@test findfirst(r"∄", u8str) == 0:-1 +@test findfirst(r"∀", u8str) == 1:1 +@test findnext(r"∀", u8str, 4) == 0:-1 +@test findfirst(r"∀", u8str) == findfirst(r"\u2200", u8str) +@test findnext(r"∀", u8str, 4) == findnext(r"\u2200", u8str, 4) +@test findfirst(r"∃", u8str) == 13:13 +@test findnext(r"∃", u8str, 16) == 0:-1 +@test findfirst(r"x", u8str) == 26:26 +@test findnext(r"x", u8str, 27) == 43:43 +@test findnext(r"x", u8str, 44) == 0:-1 +@test findfirst(r"ε", u8str) == 5:5 +@test findnext(r"ε", u8str, 7) == 54:54 +@test findnext(r"ε", u8str, 56) == 0:-1 for i = 1:endof(astr) - @test search(astr, r"."s, i) == i:i + @test findnext(r"."s, astr, i) == i:i end for i = 1:endof(u8str) if isvalid(u8str,i) - @test search(u8str, r"."s, i) == i:i + @test findnext(r"."s, u8str, i) == i:i end end -# string search with a zero-char string +# string forward search with a zero-char string for i = 1:endof(astr) - @test search(astr, "", i) == i:i-1 + @test findnext("", astr, i) == i:i-1 end for i = 1:endof(u8str) - @test search(u8str, "", i) == i:i-1 + @test findnext("", u8str, i) == i:i-1 end -@test search("", "") == 1:0 +@test findfirst("", "") == 1:0 -# string rsearch with a zero-char string +# string backward search with a zero-char string for i = 1:endof(astr) - @test rsearch(astr, "", i) == i:i-1 + @test findprev("", astr, i) == i:i-1 end for i = 1:endof(u8str) - @test rsearch(u8str, "", i) == i:i-1 + @test findprev("", u8str, i) == i:i-1 end -@test rsearch("", "") == 1:0 +@test findlast("", "") == 1:0 -# string search with a zero-char regex +# string forward search with a zero-char regex for i = 1:endof(astr) - @test search(astr, r"", i) == i:i-1 + @test findnext(r"", astr, i) == i:i-1 end for i = 1:endof(u8str) # TODO: should regex search fast-forward invalid indices? if isvalid(u8str,i) - @test search(u8str, r""s, i) == i:i-1 + @test findnext(r"", u8str, i) == i:i-1 end end -# string search with a two-char string literal -@test search("foo,bar,baz", "xx") == 0:-1 -@test search("foo,bar,baz", "fo") == 1:2 -@test search("foo,bar,baz", "fo", 3) == 0:-1 -@test search("foo,bar,baz", "oo") == 2:3 -@test search("foo,bar,baz", "oo", 4) == 0:-1 -@test search("foo,bar,baz", "o,") == 3:4 -@test search("foo,bar,baz", "o,", 5) == 0:-1 -@test search("foo,bar,baz", ",b") == 4:5 -@test search("foo,bar,baz", ",b", 6) == 8:9 -@test search("foo,bar,baz", ",b", 10) == 0:-1 -@test search("foo,bar,baz", "az") == 10:11 -@test search("foo,bar,baz", "az", 12) == 0:-1 +# string forward search with a two-char string literal +@test findfirst("xx", "foo,bar,baz") == 0:-1 +@test findfirst("fo", "foo,bar,baz") == 1:2 +@test findnext("fo", "foo,bar,baz", 3) == 0:-1 +@test findfirst("oo", "foo,bar,baz") == 2:3 +@test findnext("oo", "foo,bar,baz", 4) == 0:-1 +@test findfirst("o,", "foo,bar,baz") == 3:4 +@test findnext("o,", "foo,bar,baz", 5) == 0:-1 +@test findfirst(",b", "foo,bar,baz") == 4:5 +@test findnext(",b", "foo,bar,baz", 6) == 8:9 +@test findnext(",b", "foo,bar,baz", 10) == 0:-1 +@test findfirst("az", "foo,bar,baz") == 10:11 +@test findnext("az", "foo,bar,baz", 12) == 0:-1 # issue #9365 -# string search with a two-char UTF-8 (2 byte) string literal -@test search("ééé", "éé") == 1:3 -@test search("ééé", "éé", 1) == 1:3 -# string search with a two-char UTF-8 (3 byte) string literal -@test search("€€€", "€€") == 1:4 -@test search("€€€", "€€", 1) == 1:4 -# string search with a two-char UTF-8 (4 byte) string literal -@test search("\U1f596\U1f596\U1f596", "\U1f596\U1f596") == 1:5 -@test search("\U1f596\U1f596\U1f596", "\U1f596\U1f596", 1) == 1:5 - -# string search with a two-char UTF-8 (2 byte) string literal -@test search("éé", "éé") == 1:3 -@test search("éé", "éé", 1) == 1:3 -# string search with a two-char UTF-8 (3 byte) string literal -@test search("€€", "€€") == 1:4 -@test search("€€", "€€", 1) == 1:4 -# string search with a two-char UTF-8 (4 byte) string literal -@test search("\U1f596\U1f596", "\U1f596\U1f596") == 1:5 -@test search("\U1f596\U1f596", "\U1f596\U1f596", 1) == 1:5 - -# string rsearch with a two-char UTF-8 (2 byte) string literal -@test rsearch("ééé", "éé") == 3:5 -@test rsearch("ééé", "éé", endof("ééé")) == 3:5 -# string rsearch with a two-char UTF-8 (3 byte) string literal -@test rsearch("€€€", "€€") == 4:7 -@test rsearch("€€€", "€€", endof("€€€")) == 4:7 -# string rsearch with a two-char UTF-8 (4 byte) string literal -@test rsearch("\U1f596\U1f596\U1f596", "\U1f596\U1f596") == 5:9 -@test rsearch("\U1f596\U1f596\U1f596", "\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 5:9 - -# string rsearch with a two-char UTF-8 (2 byte) string literal -@test rsearch("éé", "éé") == 1:3 # should really be 1:4! -@test rsearch("éé", "éé", endof("ééé")) == 1:3 -# string search with a two-char UTF-8 (3 byte) string literal -@test rsearch("€€", "€€") == 1:4 # should really be 1:6! -@test rsearch("€€", "€€", endof("€€€")) == 1:4 -# string search with a two-char UTF-8 (4 byte) string literal -@test rsearch("\U1f596\U1f596", "\U1f596\U1f596") == 1:5 # should really be 1:8! -@test rsearch("\U1f596\U1f596", "\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 1:5 - -# string rsearch with a two-char string literal -@test rsearch("foo,bar,baz", "xx") == 0:-1 -@test rsearch("foo,bar,baz", "fo") == 1:2 -@test rsearch("foo,bar,baz", "fo", 1) == 0:-1 -@test rsearch("foo,bar,baz", "oo") == 2:3 -@test rsearch("foo,bar,baz", "oo", 2) == 0:-1 -@test rsearch("foo,bar,baz", "o,") == 3:4 -@test rsearch("foo,bar,baz", "o,", 1) == 0:-1 -@test rsearch("foo,bar,baz", ",b") == 8:9 -@test rsearch("foo,bar,baz", ",b", 6) == 4:5 -@test rsearch("foo,bar,baz", ",b", 3) == 0:-1 -@test rsearch("foo,bar,baz", "az") == 10:11 -@test rsearch("foo,bar,baz", "az", 10) == 0:-1 - -# array rsearch -@test rsearch(UInt8[1,2,3],UInt8[2,3],3) == 2:3 -@test rsearch(UInt8[1,2,3],UInt8[2,3],1) == 0:-1 +# string forward search with a two-char UTF-8 (2 byte) string literal +@test findfirst("éé", "ééé") == 1:3 +@test findnext("éé", "ééé", 1) == 1:3 +# string forward search with a two-char UTF-8 (3 byte) string literal +@test findfirst("€€", "€€€") == 1:4 +@test findnext("€€", "€€€", 1) == 1:4 +# string forward search with a two-char UTF-8 (4 byte) string literal +@test findfirst("\U1f596\U1f596", "\U1f596\U1f596\U1f596") == 1:5 +@test findnext("\U1f596\U1f596", "\U1f596\U1f596\U1f596", 1) == 1:5 + +# string forward search with a two-char UTF-8 (2 byte) string literal +@test findfirst("éé", "éé") == 1:3 +@test findnext("éé", "éé", 1) == 1:3 +# string forward search with a two-char UTF-8 (3 byte) string literal +@test findfirst("€€", "€€") == 1:4 +@test findnext("€€", "€€", 1) == 1:4 +# string forward search with a two-char UTF-8 (4 byte) string literal +@test findfirst("\U1f596\U1f596", "\U1f596\U1f596") == 1:5 +@test findnext("\U1f596\U1f596", "\U1f596\U1f596", 1) == 1:5 + +# string backward search with a two-char UTF-8 (2 byte) string literal +@test findlast("éé", "ééé") == 3:5 +@test findprev("éé", "ééé", endof("ééé")) == 3:5 +# string backward search with a two-char UTF-8 (3 byte) string literal +@test findlast("€€", "€€€") == 4:7 +@test findprev("€€", "€€€", endof("€€€")) == 4:7 +# string backward search with a two-char UTF-8 (4 byte) string literal +@test findlast("\U1f596\U1f596", "\U1f596\U1f596\U1f596") == 5:9 +@test findprev("\U1f596\U1f596", "\U1f596\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 5:9 + +# string backward search with a two-char UTF-8 (2 byte) string literal +@test findlast("éé", "éé") == 1:3 # should really be 1:4! +@test findprev("éé", "éé", endof("ééé")) == 1:3 +# string backward search with a two-char UTF-8 (3 byte) string literal +@test findlast("€€", "€€") == 1:4 # should really be 1:6! +@test findprev("€€", "€€", endof("€€€")) == 1:4 +# string backward search with a two-char UTF-8 (4 byte) string literal +@test findlast("\U1f596\U1f596", "\U1f596\U1f596") == 1:5 # should really be 1:8! +@test findprev("\U1f596\U1f596", "\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 1:5 + +# string backward search with a two-char string literal +@test findlast("xx", "foo,bar,baz") == 0:-1 +@test findlast("fo", "foo,bar,baz") == 1:2 +@test findprev("fo", "foo,bar,baz", 1) == 0:-1 +@test findlast("oo", "foo,bar,baz") == 2:3 +@test findprev("oo", "foo,bar,baz", 2) == 0:-1 +@test findlast("o,", "foo,bar,baz") == 3:4 +@test findprev("o,", "foo,bar,baz", 1) == 0:-1 +@test findlast(",b", "foo,bar,baz") == 8:9 +@test findprev(",b", "foo,bar,baz", 6) == 4:5 +@test findprev(",b", "foo,bar,baz", 3) == 0:-1 +@test findlast("az", "foo,bar,baz") == 10:11 +@test findprev("az", "foo,bar,baz", 10) == 0:-1 # string search with a two-char regex -@test search("foo,bar,baz", r"xx") == 0:-1 -@test search("foo,bar,baz", r"fo") == 1:2 -@test search("foo,bar,baz", r"fo", 3) == 0:-1 -@test search("foo,bar,baz", r"oo") == 2:3 -@test search("foo,bar,baz", r"oo", 4) == 0:-1 -@test search("foo,bar,baz", r"o,") == 3:4 -@test search("foo,bar,baz", r"o,", 5) == 0:-1 -@test search("foo,bar,baz", r",b") == 4:5 -@test search("foo,bar,baz", r",b", 6) == 8:9 -@test search("foo,bar,baz", r",b", 10) == 0:-1 -@test search("foo,bar,baz", r"az") == 10:11 -@test search("foo,bar,baz", r"az", 12) == 0:-1 - -@test searchindex("foo", 'o') == 2 -@test searchindex("foo", 'o', 3) == 3 - -# string searchindex with a two-char UTF-8 (2 byte) string literal -@test searchindex("ééé", "éé") == 1 -@test searchindex("ééé", "éé", 1) == 1 -# string searchindex with a two-char UTF-8 (3 byte) string literal -@test searchindex("€€€", "€€") == 1 -@test searchindex("€€€", "€€", 1) == 1 -# string searchindex with a two-char UTF-8 (4 byte) string literal -@test searchindex("\U1f596\U1f596\U1f596", "\U1f596\U1f596") == 1 -@test searchindex("\U1f596\U1f596\U1f596", "\U1f596\U1f596", 1) == 1 - -# string searchindex with a two-char UTF-8 (2 byte) string literal -@test searchindex("éé", "éé") == 1 -@test searchindex("éé", "éé", 1) == 1 -# string searchindex with a two-char UTF-8 (3 byte) string literal -@test searchindex("€€", "€€") == 1 -@test searchindex("€€", "€€", 1) == 1 -# string searchindex with a two-char UTF-8 (4 byte) string literal -@test searchindex("\U1f596\U1f596", "\U1f596\U1f596") == 1 -@test searchindex("\U1f596\U1f596", "\U1f596\U1f596", 1) == 1 +@test findfirst(r"xx", "foo,bar,baz") == 0:-1 +@test findfirst(r"fo", "foo,bar,baz") == 1:2 +@test findnext(r"fo", "foo,bar,baz", 3) == 0:-1 +@test findfirst(r"oo", "foo,bar,baz") == 2:3 +@test findnext(r"oo", "foo,bar,baz", 4) == 0:-1 +@test findfirst(r"o,", "foo,bar,baz") == 3:4 +@test findnext(r"o,", "foo,bar,baz", 5) == 0:-1 +@test findfirst(r",b", "foo,bar,baz") == 4:5 +@test findnext(r",b", "foo,bar,baz", 6) == 8:9 +@test findnext(r",b", "foo,bar,baz", 10) == 0:-1 +@test findfirst(r"az", "foo,bar,baz") == 10:11 +@test findnext(r"az", "foo,bar,baz", 12) == 0:-1 # contains with a String and Char needle @test contains("foo", "o") @test contains("foo", 'o') -# string rsearchindex with a two-char UTF-8 (2 byte) string literal -@test rsearchindex("ééé", "éé") == 3 -@test rsearchindex("ééé", "éé", endof("ééé")) == 3 -# string rsearchindex with a two-char UTF-8 (3 byte) string literal -@test rsearchindex("€€€", "€€") == 4 -@test rsearchindex("€€€", "€€", endof("€€€")) == 4 -# string rsearchindex with a two-char UTF-8 (4 byte) string literal -@test rsearchindex("\U1f596\U1f596\U1f596", "\U1f596\U1f596") == 5 -@test rsearchindex("\U1f596\U1f596\U1f596", "\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 5 - -# string rsearchindex with a two-char UTF-8 (2 byte) string literal -@test rsearchindex("éé", "éé") == 1 -@test rsearchindex("éé", "éé", endof("ééé")) == 1 -# string searchindex with a two-char UTF-8 (3 byte) string literal -@test rsearchindex("€€", "€€") == 1 -@test rsearchindex("€€", "€€", endof("€€€")) == 1 -# string searchindex with a two-char UTF-8 (4 byte) string literal -@test rsearchindex("\U1f596\U1f596", "\U1f596\U1f596") == 1 -@test rsearchindex("\U1f596\U1f596", "\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 1 - @test_throws ErrorException "ab" ∈ "abc" # issue #15723 diff --git a/test/strings/types.jl b/test/strings/types.jl index 7db39722a5349..0eefac0549c3c 100644 --- a/test/strings/types.jl +++ b/test/strings/types.jl @@ -118,9 +118,9 @@ end # search and SubString (issue #5679) let str = "Hello, world!" u = SubString(str, 1, 5) - @test rsearch(u, "World") == 0:-1 - @test rsearch(u, 'z') == 0 - @test rsearch(u, "ll") == 3:4 + @test findlast("World", u) == 0:-1 + @test findlast(equalto('z'), u) == 0 + @test findlast("ll", u) == 3:4 end # SubString created from SubString @@ -154,8 +154,8 @@ end @test parse(Float32, SubString("10",1,1)) === 1.0f0 # issue #5870 -@test !ismatch(Regex("aa"), SubString("",1,0)) -@test ismatch(Regex(""), SubString("",1,0)) +@test !contains(SubString("",1,0), Regex("aa")) +@test contains(SubString("",1,0), Regex("")) # isvalid, length, prevind, nextind for SubString{String} let s = "lorem ipsum", sdict = Dict( @@ -237,14 +237,14 @@ end for c in ('X', 'δ', '\U0001d6a5') s = convert(T, string(prefix, c, suffix)) r = reverse(s) - ri = search(r, c) + ri = findfirst(equalto(c), r) @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) + ri = findfirst(equalto(c), r) @test c == sb[reverseind(sb, ri)] == r[ri] end end