Recent

Author Topic: search and replace using backward direction  (Read 6217 times)

dcelso

  • Full Member
  • ***
  • Posts: 158
search and replace using backward direction
« on: March 18, 2013, 08:41:22 pm »
Hello to all, I'm doing a basic application like notepad, And I m trying do backward searches.
I read in this post how to do it in forward.
http://www.lazarus.freepascal.org/index.php/topic,9412.msg46746.html#msg46746

But I don't know how adapt it to do backward search.

The finddialog and search dialogs have a radiobuttion to select this option, but this code ignores it.


howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: search and replace using backward direction
« Reply #1 on: March 18, 2013, 10:25:10 pm »
Try the attached simple example you can adapt and extend.
On a new project form named Unit1 drop a memo named MText, a labeled edit named EWordToFind, a button named BFind and a TFindDialog named FindDialog1. Double-click the button to create an OnClick handler for it, and complete the code as follows:

Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Forms, Dialogs, StdCtrls, ExtCtrls, strutils, sysutils;

type

  { TForm1 }

  TForm1 = class(TForm)
    BFind: TButton;
    EWordToFind: TLabeledEdit;
    FindDialog1: TFindDialog;
    MText: TMemo;
    procedure BFindClick(Sender: TObject);
    procedure FindDialog1Find(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.BFindClick(Sender: TObject);
begin
  EWordToFind.Text:= 'the';
  MText.Lines.Text:= 'memText contains some example text' +
                     'to serve as a test for the Lazarus' +
                     'TFindDialog. It also contains a few' +
                     'repeated words, i.e. words that appear' +
                     'more than once in the same text.';
  FindDialog1.Options:= FindDialog1.Options + [frWholeWord, frHideEntireScope]; // adapt as required
  FindDialog1.FindText:= EWordToFind.Text;
  MText.SelStart:=0;
  MText.HideSelection:=False;
  FindDialog1.Execute;
end;

procedure TForm1.FindDialog1Find(Sender: TObject);
var txtToSearch, txtToFind: string;
    p: integer;
begin
  if (frDown in FindDialog1.Options) then
    begin
     txtToSearch := MText.Text;
     txtToFind:=FindDialog1.FindText;
    end
  else
   begin
    txtToSearch := ReverseString(MText.Text);
    txtToFind:= ReverseString(FindDialog1.FindText);
   end;

  if (frMatchCase in FindDialog1.Options)
    then p := PosEx(txtToFind, txtToSearch)
  else p := PosEx(Uppercase(txtToFind), Uppercase(txtToSearch));

  case (p>0) of
   False: begin
           ShowMessageFmt('The text "%s" was NOT found',[FindDialog1.FindText]);
           MText.SelLength:=0;
          end;
   True: begin
          if (frDown in FindDialog1.Options)
           then MText.SelStart:= Pred(p)
          else MText.SelStart:= Length(MText.Text) - p - Pred(Length(txtToFind));
          MText.SelLength:= Length(txtToFind);
         end;
  end;
end;

end.

dcelso

  • Full Member
  • ***
  • Posts: 158
Re: search and replace using backward direction
« Reply #2 on: March 19, 2013, 01:02:58 am »
 :o. it does not work :'(.
I'm doing anythink bad.
But I dont find it.
Here is my simple and basic example

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: search and replace using backward direction
« Reply #3 on: March 19, 2013, 03:05:11 pm »
Try the attached adaptation of your example.
Somewhere in your code you have to actually invoke the FindDialog with a call to Execute.

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: search and replace using backward direction
« Reply #4 on: March 19, 2013, 03:29:42 pm »
Code: [Select]
case (p>0) of
...
That is interesting, to case a boolean  :)  It is same as "If p>0 Then..Else.." structure.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: search and replace using backward direction
« Reply #5 on: March 19, 2013, 05:05:36 pm »
Code: [Select]
case (p>0) of
...
That is interesting, to case a boolean  :)  It is same as "If p>0 Then..Else.." structure.

I like FPC's extended case syntax, which recently has even let us use strings as case selectors.
Everyone has their own preferences for Pascal style, but I sometimes find that explicitly breaking out the two parts of a boolean condition into clearly labelled True and False sections helps me to better visualise the flow of control.
Of course, introducing an aptly named boolean variable is clearer to read and understand in some situations, but in this case, I'm not quite sure why, I prefer an alternative.
The more traditional
Code: [Select]
var found: boolean;
begin
  ...
  found := p>0;
  if found
   then ...
  else ...;
 ...
end;
might well be another coder's preference.

dcelso

  • Full Member
  • ***
  • Posts: 158
Re: search and replace using backward direction
« Reply #6 on: March 21, 2013, 04:51:24 pm »
:O, very thanks, I'm testing the code, but I see that it is very limited, for example, my current code can continue search next ocurrence, use or dont case sensitive, etc . I'll study how to add it to my currrent code, copied from here http://www.lazarus.freepascal.org/index.php/topic,9412.msg46746.html#msg46746, and add the capacity to backward search.


dcelso

  • Full Member
  • ***
  • Posts: 158
Re: search and replace using backward direction
« Reply #7 on: March 21, 2013, 08:35:02 pm »
Eureka  ;) My final customed function is the next
Code: [Select]
procedure TfrmPRGEditor.TFindDialogFind(Sender: TObject);
var
  FindS,sourceStr: String;
  IPos, FLen, SLen: Integer; {Internpos, Lengde søkestreng, lengde memotekst}
  Res : integer;
  findDialog1 : TFindDialog;
  tmpMemo : TSynMemo;
  fpos : integer;
  (*Added backward search, loop search, and search from the curren position by DCelso*)
begin
  findDialog1:= TFindDialog(Sender);
  tmpMemo := SynMemo1;
  FLen := Length(findDialog1.FindText);
  SLen := Length(tmpMemo.Text);


  // INI DCelso
  if frDown in findDialog1.Options then
  begin
    FPOS := tmpMemo.SelEnd;
    SourceStr:=Copy(tmpMemo.Text,FPos+1,SLen-FPos);
    FindS := findDialog1.FindText;
  end
  else
  begin
    FPOS := tmpMemo.SelStart;
    SourceStr:=ReverseString(Copy(tmpMemo.Text,1,FPos-1));
    FindS := ReverseString(findDialog1.FindText);
  end;
  // END DCelso

 //following 'if' added by mike
  if frMatchcase in findDialog1.Options then
     IPos := Pos(FindS, SourceStr)
  else
     IPos := Pos(AnsiUpperCase(FindS),AnsiUpperCase(SourceStr));

  If IPos > 0 then begin
   if frDown in findDialog1.Options then     // DCelso
      FPos := FPos + IPos
   else
      FPos := FPos - IPos - FLen +1;
 //   Hoved.BringToFront;       {Edit control must have focus in }
//    tmpMemo.SetFocus;
//    Self.ActiveControl := tmpMemo;
    tmpMemo.SelStart:= FPos;  // -1;   mike   {Select the string found by POS}
    setSelLength(tmpMemo, FLen);     //tmpMemo.SelLength := FLen;
   if frDown in findDialog1.Options then     // DCelso
       FPos:=FPos+FLen-1   //mike - move just past end of found item
   else
      FPos:=FPos-FLen+1   // move just past end of found item in reverestring

  end
  Else
  begin
    // DCelso
    if (MessageDlg('Find','Text was not found! Continue from the begginin?'
           , mtInformation ,  [mbYes,mbNo],0)) = mrYes then
    begin
      if frDown in findDialog1.Options then
      begin
          tmpMemo.SelStart:=0;
          tmpMemo.SelEnd:=0;
      end
      else
      begin
        tmpMemo.SelStart:= SLen;
        tmpMemo.SelEnd:= SLen;
      end;
      TFindDialogFind(Sender);
    end;
  end;             //   - also do it before exec of dialog.

end;   

 

TinyPortal © 2005-2018