## 2009. március 7., szombat

### How to do a backward search in a TRichEdit

Problem/Question/Abstract:

How to do a backward search in a TRichEdit

Solve 1:

This is how to find text searching backwards:

function FindPreviousInstanceOfSubstring(substr, S: string; startAt: Integer):
Integer;
var
i: Integer;
ch: Char;
begin
ch := substr[1];
i := startAt;
Result := 0; {assume we fail}
while i >= 1 do
begin
if S[i] = ch then
begin
if AnsiCompareStr(substr, Copy(S, i, Length(substr))) = 0 then
begin
{found an instance}
Result := i;
Break;
end;
end;
Dec(i);
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
richedit1.selstart := FindPreviousInstanceOfSubstring
(edit1.text, richedit1.text, richedit1.gettextlen) - 1;
richedit1.sellength := Length(edit1.text);
end;

Solve 2:

{Function FindTextBackwards

Parameters:
findWhat: text to find
inString: string to find it in
startAt : character index to start at (1-based)
caseSensitive: determines whether search is case-sensitive
words: if true the characters immediately surrounding a found location must not be alphanumeric

Returns: character index (1-based) of first character of a found location, or 0,

Description:
Performs a simple sequential search for a string in a larger string, starting at the specified
position and working towards the start of the string.

Error Conditions: none

Created: 27.02.99 by P. Below}

function FindTextBackwards(findWhat, inString: string; startAt: Integer;
caseSensitive, words: Boolean): Integer;
var
i, patternlen, findpos: Integer;
lastchar, firstchar: Char;
begin
Result := 0; {assume failure}
patternlen := Length(findWhat);
{Do a few sanity checks on the parameters}
if (patternlen = 0) or (startAt < patternlen) or (Length(inString) < patternlen)
then
Exit;
if not caseSensitive then
begin
{convert both strings to lower case}
findWhat := AnsiLowercase(findWhat);
inString := AnsiLowercase(inString);
end;
i := startAt;
lastchar := findWhat[patternlen];
firstchar := findWhat[1];
while (Result = 0) and (i >= patternlen) do
begin
if inString[i] = lastchar then
begin
findPos := i - patternlen + 1;
if inString[findPos] = firstchar then
begin
{We have a candidate. Compare the substring of length patternlen
starting at findPos with findWhat.
With AnsiStrLComp we can do that without having to copy the substring to
a temp string first.}
if AnsiStrLComp(@findWhat[1], @inString[findPos], patternlen) = 0 then
begin
{We have a match!}
Result := findPos;
if words then
begin
{Check the characters surrounding the hit.
For the hit to constitute a word they must not be alphanumeric.}
if (findPos > 1) and IsCharAlphanumeric(inString[findPos - 1]) then
begin
{Not a match after all}
Result := 0;
end
else
begin
if (i < Length(inString)) and IsCharAlphanumeric(inString[i + 1]) then
begin
{Not a match after all}
Result := 0;
end;
end;
end;
end;
end;
end;
Dec(i);
end;
end;

Here's how to use it:

procedure TForm1.Button1Click(Sender: TObject);
var
findPos: Integer;
begin
findPos := FindTextBackwards(findEdit.Text, richedit1.Text, richedit1.selstart + 1,
caseCheckbox.checked, wordsCheckbox.checked);
if findPos > 0 then
begin
with richedit1 do
begin
selstart := findPos - 1;
sellength := findEdit.GetTextLen;
perform(em_scrollcaret, 0, 0);
setfocus;
end;
end
else