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
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Build system changes
New library functions
---------------------

* `findfirst`, `findlast`, `findnext` and `findprev` now accept a character as first argument
to search for that character in a string passed as the second argument ([#31664]).
* New `findall(pattern, string)` method where `pattern` is a string or regex ([#31834]).

Standard library changes
Expand Down
78 changes: 78 additions & 0 deletions base/strings/search.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,25 @@ julia> findfirst("Julia", "JuliaLang")
findfirst(pattern::AbstractString, string::AbstractString) =
findnext(pattern, string, firstindex(string))

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

Find the first occurrence of character `ch` in `string`.

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

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::AbstractChar, 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 +274,26 @@ julia> findnext("Lang", "JuliaLang", 2)
"""
findnext(t::AbstractString, s::AbstractString, i::Integer) = _search(s, t, i)

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

Find the next occurrence of character `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::AbstractChar, string::AbstractString, ind::Integer) =
findnext(==(ch), string, ind)

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

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

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

Find the last occurrence of character `ch` in `string`.

!!! 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::AbstractChar, 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 +486,26 @@ julia> findprev("Julia", "JuliaLang", 6)
"""
findprev(t::AbstractString, s::AbstractString, i::Integer) = _rsearch(s, t, i)

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

Find the previous occurrence of character `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::AbstractChar, string::AbstractString, ind::Integer) =
findprev(==(ch), string, ind)

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

Expand Down
39 changes: 39 additions & 0 deletions test/strings/search.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,28 @@ for str in [astr, GenericString(astr)]
@test_throws BoundsError findnext(isequal('a'), str, nextind(str,lastindex(str))+1)
end

for str in [astr, GenericString(astr)]
@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
Expand All @@ -61,6 +83,23 @@ for str in [astr]
@test findlast(isequal('\n'), str) == 14
end

for str in [astr]
@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
for str in (u8str, GenericString(u8str))
@test_throws BoundsError findnext(isequal('z'), str, 0)
Expand Down