Home > Blockchain >  How to search for different occurences of strings using POS
How to search for different occurences of strings using POS

Time:04-27

I'm trying to create a function that is similar to Delphi's pos function, but that i could pass different strings to be searched, instead of only one. So i could call the function like this :

multipos('word1#word2#word3','this is a sample text with word2',false); 
// will return 'word2'

The function would return which string was found.

The code i did is below and it's working but it's too slow. How could i improve the speed of this code ?

function multipos(needles,key: string; requireAll: boolean): string;
var
  k: array [1 .. 50] of string;
  i, j: integer;
  r, aux: string;
  flag: boolean;
begin
  if trim(key) = '' then
    Result := ''
  else
    try
      r := '';
      Result := '';
      j := 1;
      for i := 1 to 50 do
        k[i] := '';

      for i := 1 to length(needles) do
      begin
        if needles[i] <> '#' then
          aux := aux   needles[i]
        else
        begin
          k[j] := aux;
          Inc(j);
          aux := '';
        end;
        if j >= 50 then
          break;
      end;
      if aux <> '' then
        k[j] := aux;

      for i := 1 to j do
      begin
        if k[i] = '' then
          break
        else
          if pos(lowercase(k[i]), lowercase(key)) > 0 then
          begin
            if not requireAll then
            begin
              Result := k[i];
              break;
            end
            else
            begin
              r := r   k[i]   ',';
              flag := i = j;
              if not flag then
                flag := k[i   1] = '';
              if flag then
              begin
                Result := r;
              end;
            end;
          end
          else
            if requireAll then
            begin
              break;
            end;
      end;
    except
      on e: exception do
      begin
        Result := '';
      end;
    end;
end;

CodePudding user response:

Consider to pass the items as an array, like:

function Multipos(A: array of string; const S: string): string;
begin
  for var E in A do
    if Pos(E, S) > 0 then
      Exit(E);
  Result := ''; // Nothing found
end;

// sample call
Multipos(['word1', 'word2', 'word3'], 'this is a sample text with word2');`

To implement RequireAll functionality, stop on first failure. Just check what to return in that case.

Also, TStrings/TStringList could work for your needs. Check it's Delimiter and DelimitedText properties.

CodePudding user response:

As you didn't specify a Delphi version, I simply assume the latest:

function multipos(const needles,key: string; requireAll: boolean): string;
var
  lst: TStringList;
begin
  lst := TStringList.Create;
  try
    var lowerkey := key.ToLower; // do this only once
    for var needle in needles.Split(['#']) do begin
      if lowerkey.Contains(needle.ToLower) then begin
        if not requireAll then 
          Exit(needle);
        lst.Add(needle);
      end;
    end;
    Result := lst.CommaText;
  finally
    lst.Free;
  end;
end;

CodePudding user response:

The array solution by Marcodor is good. Here is a TStringList alternative:

function multipos(SubStrs: TStringList; Str: string; RequireAll: Boolean): string;
var
  i: Integer;
begin
  if (not Str.IsEmpty) and (not SubStrs.Count < 1) then
  begin
    Result := '';
    for i := 0 to SubStrs.Count - 1 do
      if Pos(SubStrs[i], Str) > 0 then
        Result := Result   Copy(Str, Pos(SubStrs[i], Str), SubStrs[i].Length)
      else if RequireAll then
        Result := '';
  end;
end;

var
  myList: TStringList;

begin
  myList := TStringList.Create;
  myList.Delimiter := '#';
  myList.DelimitedText := 'word1#word2#word3';
  Writeln(multipos(myList, 'this word1is a sample word3 text with word2', False));
end.

Obviously you'll need system.classes for the StringList. And perhaps some better checking if everything is in order before accessing the parameters, but it works for RequireAll True and False.

  • Related