0

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; 
3
  • 1
    Your sample call and the working code have mismatching signatures. What is needle? Why are you limiting the array k to 50? What exactly is your multipos supposed to return on that example call? Commented Apr 26, 2022 at 14:20
  • @Sherlock70 I fixed the signature and edited the question to clarify. I'm limiting to 50 due to performance issues Commented Apr 26, 2022 at 14:23
  • I am still unsure what the requireAll option actually means. My interpretation is: return all needles that are present in key. Commented Apr 26, 2022 at 15:22

3 Answers 3

5

Consider to pass the items as an array, like:

function Multipos(const 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 calls Multipos(['word1', 'word2', 'word3'], 'sample text with word2'); Multipos('word1#word2#word3'.Split(['#']), '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.

Sign up to request clarification or add additional context in comments.

Comments

1

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; 

7 Comments

The fact it will need to create and free a stringlist every time the function is called, won't make this version slower ?
Usually object creation and destruction is pretty fast in Delphi. So unless you have measured a significant performance drop I wouldn't bother. Always the first goal is to make it work - then make it fast only if necessary.
Why did you chose to not inline declare lst, too?
@AmigoJack, because in MMX the try-finally wizard doesn't support it (yet).
@UweRaabe, why to add one by one all needles in the list as anyway at the end, if reached, it will contain all input items.. best to simply replace # with a comma
|
1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.