2

I want to count how many times a String occurs in another String in Pascal Script like shown in the below example.

I've seen the answer to Delphi: count number of times a string occurs in another string, but there is no PosEx function in Pascal Script.

MyString := 'Hello World!, Hello World!, Hello World!, Hello World!';

If I count the number of times Hello or World occurs here, the result should be 4.

If I count the number of times , (comma) occurs here, the result should be 3.

UPDATE

The following function works, but it copies given String again to a new Variable, and deletes parts of Strings, so it works slowly.

function OccurrencesOfSubString(S, SubStr: String): Integer;
var
  DSStr: String;
begin
  if Pos(SubStr, S) = 0 then
    Exit
  else
    DSStr := S;
  Repeat
    if Pos(SubStr, S) <> 0 then
    Inc(Result);
    Delete(DSStr, Pos(SubStr, DSStr), Length(Copy(DSStr, Pos(SubStr, DSStr), Length(SubStr))));
  Until Pos(SubStr, DSStr) = 0;
end;
Community
  • 1
  • 1
GTAVLover
  • 1,407
  • 3
  • 22
  • 41

1 Answers1

3

Your implementation is generally correct.

There are some optimizations to be made and useless code to be removed:

  • The second test for if Pos(SubStr, S) <> 0 (within repeat) is pointless. It's true always. You are testing S, which was tested at the function start already. And the DSStr is already tested in the until.
  • You should save Pos(SubStr, DSStr) to a variable not to call it multiple times.
  • Length(Copy(DSStr, Pos(SubStr, DSStr), Length(SubStr))) is actually the same as Length(SubStr).
  • No need to copy the S to DSStr. You can work directly with the S. It's by-value parameter, so you do not modify the variable that you use to call the function.
  • Replace the initial Pos(SubStr, S) = 0 check with the same check in the loop to save one Pos call.

Optimized version of your code:

function OccurrencesOfSubString(S, SubStr: String): Integer;
var
  P: Integer;
begin
  Result := 0;
  repeat
    P := Pos(SubStr, S);
    if P > 0 then
    begin
      Inc(Result);
      Delete(S, P, Length(SubStr));
    end;
  until P = 0;
end;

But actually with the Inno Setup StringChange function (which Delphi does not have), you do not have to code any algorithm yourself.

function OccurrencesOfSubString(S, SubStr: String): Integer;
begin
  Result := StringChange(S, SubStr, '');
end; 

This was inspired by the @RobertFrank's answer to Delphi: count number of times a string occurs in another string.

While the use of the StringChange looks inefficient (as it has significant side effects), it's actually faster. Probably because it is implemented in Pascal, not in Pascal Script.

Tested with 3 million calls to:

OccurrencesOfSubString('Hello World!, Hello World!, Hello World!, Hello World!', 'Hello')
  • With StringChange: 11 seconds
  • My optimized version of your code: 49 seconds
  • Your original code: 99 seconds

Though for few calls, all implementations are good enough.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • Thank You! works!, As I hadn't enough time, I became late to Update my question with my function. :-( – GTAVLover Oct 07 '16 at 07:11
  • Thank You For Excellent Help! If I work directly with the `S`, aren't the contents of `S` will be lost after calling your optimized version of my function? What did you mean by By-Value? – GTAVLover Oct 07 '16 at 10:58
  • If you declare the parameter as `S: string`, it's passed by value (by copy), so any modification to the `S` in the function, is done on a copy of the string and won't affect the variable used to call the function. Note that such function can be calls with a constant string too. - As opposite to a parameter declared as `var S: string` - This is passed by reference. Any modification to the `S` will modify the variable used to call the function - And consequently you cannot use a constant string for the parameter, as the constant cannot be modified. – Martin Prikryl Oct 07 '16 at 11:12
  • 1
    See also [Call by value](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value) and [Call by reference](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_reference). – Martin Prikryl Oct 07 '16 at 11:15