Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add findfirst, findlast for searching char in strings #31664

Merged
merged 17 commits into from
Jun 3, 2019
Merged
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Build system changes
New library functions
---------------------

* `findfirst`, `findlast`, `findnext` and `findprev` now addresses search for a character in a string ([#31664]).
eulerkochy marked this conversation as resolved.
Show resolved Hide resolved

Standard library changes
------------------------
Expand Down
80 changes: 79 additions & 1 deletion base/strings/search.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,29 @@ julia> findfirst("Julia", "JuliaLang")
1:5
```
"""
findfirst(pattern::AbstractString, string::AbstractString) =
findfirst(pattern::AbstractString, string::AbstractString) =
eulerkochy marked this conversation as resolved.
Show resolved Hide resolved
findnext(pattern, string, firstindex(string))

"""
findfirst(ch::Char, string::AbstractString)

Find the first occurrence of `ch` in `string`. Equivalent to
[`findfirst(isequal(ch), string)`](@ref).
eulerkochy marked this conversation as resolved.
Show resolved Hide resolved

eulerkochy marked this conversation as resolved.
Show resolved Hide resolved
!!! compat "Julia 1.3"
This function requires at least Julia 1.3.
eulerkochy marked this conversation as resolved.
Show resolved Hide resolved

# Examples
```jldoctest
julia> findfirst('a', "happy")
2

julia> findfirst('z', "happy") === nothing
true
```
"""
findfirst(ch::Char, string::AbstractString) = findfirst(==(ch), string)

# AbstractString implementation of the generic findnext interface
function findnext(testf::Function, s::AbstractString, i::Integer)
z = ncodeunits(s) + 1
Expand Down Expand Up @@ -255,6 +275,25 @@ julia> findnext("Lang", "JuliaLang", 2)
"""
findnext(t::AbstractString, s::AbstractString, i::Integer) = _search(s, t, i)

"""
findnext(ch::Char, string::AbstractString, start::Integer)

Find the next occurrence of `ch` in `string` starting at position `start`.

!!! compat "Julia 1.3"
This function requires at least Julia 1.3.
eulerkochy marked this conversation as resolved.
Show resolved Hide resolved

# Examples
```jldoctest
julia> findnext(`z`, "Hello to the world", 1) === nothing
true

julia> findnext(`o`, "Hello to the world", 6)
8
```
"""
findnext(ch::Char, string::AbstractString, ind::Integer) = findnext(==(ch), string, ind)

"""
findlast(pattern::AbstractString, string::AbstractString)

Expand All @@ -273,6 +312,26 @@ julia> findfirst("Julia", "JuliaLang")
findlast(pattern::AbstractString, string::AbstractString) =
findprev(pattern, string, lastindex(string))

"""
findlast(ch::Char, string::AbstractString)

Find the last occurrence of `ch` in `string`. Equivalent to
[`findlast(isequal(ch), string)`](@ref).

!!! compat "Julia 1.3"
This function requires at least Julia 1.3.
eulerkochy marked this conversation as resolved.
Show resolved Hide resolved

# Examples
```jldoctest
julia> findlast('p', "happy")
4

julia> findlast('z', "happy") === nothing
true
```
"""
findlast(ch::Char, string::AbstractString) = findlast(==(ch), string)

# AbstractString implementation of the generic findprev interface
function findprev(testf::Function, s::AbstractString, i::Integer)
if i < 1
Expand Down Expand Up @@ -428,6 +487,25 @@ julia> findprev("Julia", "JuliaLang", 6)
"""
findprev(t::AbstractString, s::AbstractString, i::Integer) = _rsearch(s, t, i)

"""
findprev(ch::Char, string::AbstractString, start::Integer)

Find the previous occurrence of `ch` in `string` starting at position `start`.

!!! compat "Julia 1.3"
This function requires at least Julia 1.3.
eulerkochy marked this conversation as resolved.
Show resolved Hide resolved

# Examples
```jldoctest
julia> findprev('z', "Hello to the world", 18) === nothing
true

julia> findprev('o', "Hello to the world", 18)
15
```
"""
findprev(ch::Char, string::AbstractString, ind::Integer) = findprev(==(ch), string, ind)

"""
occursin(needle::Union{AbstractString,Regex,AbstractChar}, haystack::AbstractString)

Expand Down
64 changes: 33 additions & 31 deletions test/strings/search.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,41 +24,43 @@ end

# ascii forward search
for str in [astr, GenericString(astr)]
@test_throws BoundsError findnext(isequal('z'), str, 0)
eulerkochy marked this conversation as resolved.
Show resolved Hide resolved
@test_throws BoundsError findnext(isequal('∀'), str, 0)
@test findfirst(isequal('x'), str) == nothing
@test findfirst(isequal('\0'), str) == nothing
@test findfirst(isequal('\u80'), str) == nothing
@test findfirst(isequal('∀'), str) == nothing
@test findfirst(isequal('H'), str) == 1
@test findfirst(isequal('l'), str) == 3
@test findnext(isequal('l'), str, 4) == 4
@test findnext(isequal('l'), str, 5) == 11
@test findnext(isequal('l'), str, 12) == nothing
@test findfirst(isequal(','), str) == 6
@test findnext(isequal(','), str, 7) == nothing
@test findfirst(isequal('\n'), str) == 14
@test findnext(isequal('\n'), str, 15) == nothing
@test_throws BoundsError findnext(isequal('ε'), str, nextind(str,lastindex(str))+1)
@test_throws BoundsError findnext(isequal('a'), str, nextind(str,lastindex(str))+1)
@test_throws BoundsError findnext('z', str, 0)
@test_throws BoundsError findnext('∀', str, 0)
@test findfirst('x', str) == nothing
@test findfirst('\0', str) == nothing
@test findfirst('\u80', str) == nothing
@test findfirst('∀', str) == nothing
@test findfirst('H', str) == 1
@test findfirst('l', str) == 3
@test findfirst('e', str) == 2
@test findfirst('u', str) == nothing
@test findnext('l', str, 4) == 4
@test findnext('l', str, 5) == 11
@test findnext('l', str, 12) == nothing
@test findfirst(',', str) == 6
@test findnext(',', str, 7) == nothing
@test findfirst('\n', str) == 14
@test findnext('\n', str, 15) == nothing
@test_throws BoundsError findnext('ε', str, nextind(str,lastindex(str))+1)
@test_throws BoundsError findnext('a', str, nextind(str,lastindex(str))+1)
end

# ascii backward search
for str in [astr]
@test findlast(isequal('x'), str) == nothing
@test findlast(isequal('\0'), str) == nothing
@test findlast(isequal('\u80'), str) == nothing
@test findlast(isequal('∀'), str) == nothing
@test findlast(isequal('H'), str) == 1
@test findprev(isequal('H'), str, 0) == nothing
@test findlast(isequal('l'), str) == 11
@test findprev(isequal('l'), str, 5) == 4
@test findprev(isequal('l'), str, 4) == 4
@test findprev(isequal('l'), str, 3) == 3
@test findprev(isequal('l'), str, 2) == nothing
@test findlast(isequal(','), str) == 6
@test findprev(isequal(','), str, 5) == nothing
@test findlast(isequal('\n'), str) == 14
@test findlast('x', str) == nothing
@test findlast('\0', str) == nothing
@test findlast('\u80', str) == nothing
@test findlast('∀', str) == nothing
@test findlast('H', str) == 1
@test findprev('H', str, 0) == nothing
@test findlast('l', str) == 11
@test findprev('l', str, 5) == 4
@test findprev('l', str, 4) == 4
@test findprev('l', str, 3) == 3
@test findprev('l', str, 2) == nothing
@test findlast(',', str) == 6
@test findprev(',', str, 5) == nothing
@test findlast('\n', str) == 14
end

# utf-8 forward search
Expand Down