Method for counting characters in string? count("a", "batman") vs. count('a', "batman")

It seems like there should be a valid method for a calling count with a character and a string.

count("a", "batman")  # returns 2 as expected
count('a', "batman")  # ERROR: MethodError: objects of type Char are not callable
count(==('a'), "batman") #  returns 2, an annoying workaround

Is there a reason why this count method isn’t supported. Thoughts?

2 Likes

The function that should do the job is this one (from base/regex.jl):

 function count(t::Union{AbstractString,Regex}, s::AbstractString; overlap::Bool=false)
           n = 0
           i, e = firstindex(s), lastindex(s)
           while true
               r = findnext(t, s, i)
               isnothing(r) && break
               n += 1
               j = overlap || isempty(r) ? first(r) : last(r)
               j > e && break
               @inbounds i = nextind(s, j)
           end
           return n
       end

If one adds “AbstractChar” to the union, that function would be called and results what is expected:

julia> function mycount(t::Union{AbstractString,Regex,AbstractChar}, s::AbstractString; overlap::Bool=false)
           n = 0
           i, e = firstindex(s), lastindex(s)
           while true
               r = findnext(t, s, i)
               isnothing(r) && break
               n += 1
               j = overlap || isempty(r) ? first(r) : last(r)
               j > e && break
               @inbounds i = nextind(s, j)
           end
           return n
       end
mycount (generic function with 2 methods)

julia> mycount("a","batman")
2

julia> mycount('a',"batman")
2

I am not sure if there is any bad implication on doing that, but it seems a simple fix.

3 Likes

Thanks Leandro. Indeed it seems like a quick fix. I tested pretty much that exact code after posting.

It seems like such an obvious thing that I figured there would have been some discussion about and possibly a reason for not implementing it.

Please feel free to make a PR with this addition and a testcase.

1 Like

I’ll do it carefully asap.

Edit: done (https://github.com/JuliaLang/julia/pull/38675

I have not much experience with this, but I hope that is fine.

7 Likes

There is a similar possible issue with findall:

julia> findall("a","batman")
2-element Array{UnitRange{Int64},1}:
 2:2
 5:5

julia> findall('a',"batman")
ERROR: MethodError: no method matching findall(::Char, ::String)

julia> findall(==('a'),"batman")
2-element Array{Int64,1}:
 2
 5

Should we add a new method to findall? The error message is not as bad as that of count , but it seems reasonable to expect findall to find all chars and return their positions.

Yes, it is an omission as findfirst and findlast already work with a Char as the first argument.

2 Likes

I have added a method there for findall as well.

2 Likes