Search code examples
delphitmemo

How can I select the second copy of a text in a TMemo


I have a TMemo with text inside it, for example:

Text1
Hello World!
Sky
Text123

I use a simple function to select the first time a text was found

Memo1.SelStart := Pos(AnsiLowerCase('Text'), AnsiLowerCase(Memo1.Text)) - 1;
    Memo1.SelLength := Length('Text');
    Memo1.SetFocus;

I used AnsiLowerCase so I can find text without the need for proper capitalization.

So, how can I select the second time "text" appears in the Memo?


Solution

  • You can use the Offset parameter of the Pos function in order to avoid starting search from the beginning and skip the first occurrence.

    Locates a substring in a given string.

    The Pos method returns the index of the first occurence of Substr in Str, starting the search at Offset.

    This method returns zero if Substr is not found or Offset is invalid (for example, if Offset exceeds the String length or is less than 1).

    The Offset argument is optional. Offset is set to 1 by default, if no value for Offset is specified it takes the default value to start the search from the beginning.

    Notes:

    Pos uses one-based array indexing even in platforms where the strings are zero-based.

    Pos method is equivalent to System.StrUtils.PosEx.

    For example:

    Picture displaying an example form with a memo, text edit and findnext button

    procedure SearchNext(AMemo : TMemo; const ATextToSearch : string; ACycle : Boolean = True);
    var
      Offset : Integer;
    begin
      //adjusting offset
      Offset := AMemo.SelStart + AMemo.SelLength + 1;
      if(Offset >= Length(AMemo.Text)) then
        Offset := 1;
    
      //searching
      Offset := Pos(AnsiLowerCase(ATextToSearch), AnsiLowerCase(AMemo.Text), Offset);
      if(Offset > 0) then
      begin
        //selecting found text
        AMemo.SelStart := Offset - 1;
        AMemo.SelLength := Length(ATextToSearch);
        AMemo.SetFocus;
      end else
      begin
        //recursion from the beginning
        if(ACycle and (AMemo.SelStart + AMemo.SelLength <> 0)) then
        begin
          AMemo.SelStart := 0;
          SearchNext(AMemo, ATextToSearch, True);
        end;
      end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      SearchNext(Memo1, Edit1.Text);
    end;