Getting count of occurrences for X in string
-
21-12-2019 - |
Question
Im looking for a function like Pythons
"foobar, bar, foo".count("foo")
Could not find any functions that seemed able to do this, in a obvious way. Looking for a single function or something that is not completely overkill.
Solution
I think that right now the closest built-in thing to what you're after is the length of a split
(minus 1). But it's not difficult to specifically create what you're after.
I could see a searchall
being generally useful in Julia's Base, similar to matchall
. If you don't care about the actual indices, you could just use a counter instead of growing the idxs
array.
function searchall(s, t, overlap::Bool=false)
idxfcn = overlap ? first : last
r = search(s, t)
idxs = Array(typeof(r), 0) # Or to only count: n = 0
while last(r) > 0
push!(idxs, r) # n += 1
r = search(s, t, idxfcn(r) + 1)
end
idxs # return n
end
OTHER TIPS
What about regexp ?
julia> length(matchall(r"ba", "foobar, bar, foo"))
2
Sorry to post another answer instead of commenting previous one, but i've not managed how to deal with code blocks in comments :)
If you don't like regexps, maybe a tail recursive function like this one (using the search() base function as Matt suggests) :
function mycount(what::String, where::String)
function mycountacc(what::String, where::String, acc::Int)
res = search(where, what)
res == 0:-1 ? acc : mycountacc(what, where[last(res) + 1:end], acc + 1)
end
what == "" ? 0 : mycountacc(what, where, 0)
end
This is simple and fast (and does not overflow the stack):
function mycount2(where::String, what::String)
numfinds = 0
starting = 1
while true
location = search(where, what, starting)
isempty(location) && return numfinds
numfinds += 1
starting = location.stop + 1
end
end
Julia-1.0
update:
For single-character count within a string (in general, any single-item count within an iterable), one can use Julia's count
function:
julia> count(i->(i=='f'), "foobar, bar, foo")
2
(The first argument is a predicate that returns a ::Bool).
For the given example, the following one-liner should do:
julia> length(collect(eachmatch(r"foo", "bar foo baz foo")))
2
Adding an answer to this which allows for interpolation:
julia> a = ", , ,";
julia> b = ",";
julia> length(collect(eachmatch(Regex(b), a)))
3
Actually, this solution breaks for some simple cases due to use of Regex. Instead one might find this useful:
"""
count_flags(s::String, flag::String)
counts the number of flags `flag` in string `s`.
"""
function count_flags(s::String, flag::String)
counter = 0
for i in 1:length(s)
if occursin(flag, s)
s = replace(s, flag=> "", count=1)
counter+=1
else
break
end
end
return counter
end