diff --git a/NEWS.md b/NEWS.md index 40f3e00e02a28..48aebc9344980 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ Julia v1.7 Release Notes New language features --------------------- - +* `count` and `findall` now accept an `AbstractChar` argument to search for a character in a string ([#38675]). Language changes ---------------- diff --git a/base/regex.jl b/base/regex.jl index 8ee07fbc006cc..d03938f3177ad 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -396,9 +396,29 @@ function findall(t::Union{AbstractString,AbstractPattern}, s::AbstractString; ov return found end +""" + findall(c::AbstractChar, s::AbstractString) + +Return a vector `I` of the indices of `s` where `s[i] == c`. If there are no such +elements in `s`, return an empty array. + +# Examples +```jldoctest +julia> findall('a', "batman") +2-element Vector{Int64}: + 2 + 5 +``` + +!!! compat "Julia 1.7" + This method requires at least Julia 1.7. +""" +findall(c::AbstractChar, s::AbstractString) = findall(isequal(c),s) + + """ count( - pattern::Union{AbstractString,AbstractPattern}, + pattern::Union{AbstractChar,AbstractString,AbstractPattern}, string::AbstractString; overlap::Bool = false, ) @@ -411,8 +431,11 @@ original string, otherwise they must be from disjoint character ranges. !!! compat "Julia 1.3" This method requires at least Julia 1.3. + +!!! compat "Julia 1.7" + Using a character as the pattern requires at least Julia 1.7. """ -function count(t::Union{AbstractString,AbstractPattern}, s::AbstractString; overlap::Bool=false) +function count(t::Union{AbstractChar,AbstractString,AbstractPattern}, s::AbstractString; overlap::Bool=false) n = 0 i, e = firstindex(s), lastindex(s) while true diff --git a/test/regex.jl b/test/regex.jl index 595a3417cd33f..77a7545eaecef 100644 --- a/test/regex.jl +++ b/test/regex.jl @@ -64,12 +64,22 @@ @test findall(r"\w+", "foo bar", overlap=true) == [1:3, 2:3, 3:3, 5:7, 6:7, 7:7] @test all(findall(r"\w*", "foo bar") .=== [1:3, 4:3, 5:7, 8:7]) # use === to compare empty ranges @test all(findall(r"\b", "foo bar") .=== [1:0, 4:3, 5:4, 8:7]) # use === to compare empty ranges + # with Char as argument + @test findall('a', "batman") == [2, 5] + @test findall('→', "OH⁻ + H₃CBr → HOH₃CBr⁻ → HOCH₃ + Br⁻") == [17, 35] + @test findall('a', "") == Int[] + @test findall('c', "batman") == Int[] # count @test count(r"\w+", "foo bar") == 2 @test count(r"\w+", "foo bar", overlap=true) == 6 @test count(r"\w*", "foo bar") == 4 @test count(r"\b", "foo bar") == 4 + # count with char as argument + @test count('a', "batman") == 2 + @test count('a', "aaa", overlap=true) == 3 + @test count('a', "") == 0 + @test count('→', "OH⁻ + H₃CBr → (HOH₃CBr⁻)† → HOCH₃ + Br⁻") == 2 # Unnamed subpatterns let m = match(r"(.)(.)(.)", "xyz")