Counting the number of a phrase occurrences in a string

What would you say more efficient if used in a loop:

CountOccurrences = UBound(FullString.Split(phrase))
CountOccurrences = FullString.CountFields(phrase)-1

Or maybe there’s something even better that I’m not taking into consideration?

CountFields should skip the creation of an array and a lot of little strings.

1 Like

That’s what I thought but I remember reading somewhere we should avoid using it in a loop if possible, any thoughts?

Well, for a while or for loop, please put the upper bound of the expression into a local variable to avoid it being evaluated each time the loop loops.

so instead of

for I as integer = 1 to CountFields(...)

you do this:

dim u as integer = CountFields(...)
for I as integer = 1 to u

and you avoid CountFields() being called dozens of times.

1 Like

@Christian_Schmitz Ohhh no, sorry I wasn’t clear enough, I’m using it inside the loop, not to construct the loop.

Then much better to split it into an array before the loop.

Haha, but the string is changing with every loop iteration, that’s the whole point :smiley:

Perhaps it would be better to post the whole loop.

1 Like

Okay, I simplified my loop only to make the dilemma obvious:

s = TextArea1.ReplaceLineEndings(EndOfLine.Windows)
aRow = Split(s,endofline)
For index As Integer = 0 To aRow.LastIndex
  Var CountOccurrences As Int16 = UBound(aRow(index).Split(phrase))
  If CountOccurrences > 1 Then
    REM do something...
  End If

@Kem_Tekinay By the way, this loop is on TextArea1.TextChange event
So it is being called each time the user edit TextArea1, and it may be about 100 lines long for some users.

I haven’t thought about this too hard, but right after defining s could you do

result = s.Split(phrase)

and then figure out which line each phrase is on by counting the endoflines in each part of result? You wouldn’t need a loop at all.

A better thought out (but not tested) explanation:

s = TextArea1.ReplaceLineEndings(EndOfLine.Windows)
foundResult = s.split(phrase)

for index as integer = 0 to ubound(foundResult)
   var lineNumber as Integer = foundResult(index).CountFields(endofline)
   // Do something with lineNumber

Thanks but no @Bill_Gookin :smiley:
The phrase could show up almost in every line, I only need to make sure it appears 1 time in each line.

Could you do a regex search for “phrase” between endoflines? @Kem_Tekinay might have an idea.

If you’re not interested in how many times it appears, use IndexOf instead.

if aRow( index ).IndexOf( phrase ) <> -1 then ...

Also, there is no reason to cast to an Int16, and that would likely make your code (a tiny bit) slower.

Nice @Kem_Tekinay but I do care about how many times it appears, or to put it more precisely, it can only be present 1 time in each line.

Got it. I’d use CountFields.

1 Like

Great talk, thank you guys very much :heart_eyes:

1 Like