Reputation: 15
I have created a small program the read a text file.
Once the text file is opened in a RichEdit, I want to change the background color of lines that contain a certain string, or to hide all lines that do not contain the string. Is it possible?
I have tried to search for the string, but I haven't any idea of how to do what I'm asking for.
function SearchText(Control: TCustomEdit; Search: string; SearchOptions: TSearchOptions): Boolean;
var
Text: string;
Index: Integer;
begin
if soIgnoreCase in SearchOptions then
begin
Search := UpperCase(Search);
Text := UpperCase(Control.Text);
end
else
Text := Control.Text;
Index := 0;
if not (soFromStart in SearchOptions) then
Index := PosEx(Search, Text, Control.SelStart + Control.SelLength + 1);
if (Index = 0) and
((soFromStart in SearchOptions) or
(soWrap in SearchOptions)) then
Index := PosEx(Search, Text, 1);
Result := Index > 0;
if Result then
begin
Control.SelStart := Index - 1;
Control.SelLength := Length(Search);
end;
end;
Upvotes: 0
Views: 903
Reputation: 597941
Searching and filtering text before putting it into the RichEdit is best.
However, if the text is already loaded in the RichEdit, TRichEdit
does have a FindText()
method you can use, you should not be searching its Text
property manually. For example:
function SearchText(Control: TCustomRichEdit; const Search: string; SearchOptions: TSearchOptions): Boolean;
var
StartPos, SearchLen, Index: Integer;
Options: TSearchTypes;
begin
if soIgnoreCase in SearchOptions then
Options := []
else
Options := [stMatchCase];
if soFromStart in SearchOptions then
begin
StartPos := 0;
SearchLen := Control.GetTextLen;
Index := Control.FindText(Search, StartPos, SearchLen, Options);
end else
begin
StartPos := Control.SelStart + Control.SelLength;
SearchLen := Control.GetTextLen - StartPos;
Index := Control.FindText(Search, StartPos, SearchLen, Options);
if (Index = -1) and (soWrap in SearchOptions) then
Index := Control.FindText(Search, 0, StartPos, Options);
end;
Result := Index <> -1;
if Result then
begin
Control.SelStart := Index;
Control.SelLength := Length(Search);
end;
end;
That being said, setting the background color of a line, or removing a line (there is no option to "hide" a line), is fairly simple.
Given any character index, you can send the RichEdit an EM_LINEFROMCHAR
message to determine the line index that the character appears on.
You can then remove the line from the RichEdit by using the TRichEdit.Lines.Delete()
method.
To set the line's background color takes a few steps:
send the RichEdit EM_LINEINDEX
and EM_LINELENGTH
messages to determine the line's starting and ending character indexes.
set the RichEdit's SelStart
and SelLength
properties (or send the RichEdit an EM_EXSETSEL
message).
send the RichEdit an EM_SETCHARFORMAT
message, specifying the SCF_SELECTION flag and using the CHARFORMAT2
record, to set the background color of the selection.
Upvotes: 1
Reputation: 109003
This is kind of a poor SO question, because it is a bit like "please write the code for me".
The natural approach would be to find the independent parts of the problem:
How to represent an array of strings (lines) in Delphi?
How to load a text file in Delphi into some in-memory array of strings?
How to search for a substring in a string in Delphi?
How to filter a Delphi in-memory array of strings? [This is trivial if you know 1 and has heard of loops. Doing it efficiently is slightly more interesting.]
How to populate a Delphi TRichEdit
control?
Indeed, if you know the answers to 1--5, doing what you want is trivial!
I might seem like a very grumpy old man now, but I think I do have a very important point about how to approach a programming problem.
Anyhow, let us address one issue at a time:
The old-school approach of a array of string
, today written TArray<string>
works. This is a dynamic array of strings. Since Delphi dynamic arrays are managed by the compiler, they are convenient because you don't need to create and free them manually. However, they are a bit low-level and are sometimes misused.
Probably a better alternative for you is to use the TStringList
class.
In IOUtils
, you find TFile.ReadAllLines
which takes a file name and returns the contents of the (text) file as an array of strings.
Or use TStringList.LoadFromFile
if you have a TStringList
.
Traditionally, you would use the Pos
function. But today you can use the string
helper: MyString.Contains()
. Obviously, you need to decide if you want to treat CAPITALS and small letters as identical or not.
Use a trivial for
or for in
loop to populate a second array from the original array, based on the test from 3.
If you have a TStringList
, just use TRichEdit.Lines.Assign
.
Putting it all together, using a fairly smart combination of string
arrays and TStringList
:
procedure TForm1.Button1Click(Sender: TObject);
begin
var Lines := TFile.ReadAllLines('K:\test.txt');
var FilteredLines := TStringList.Create;
try
for var Line in Lines do
if Line.Contains('MyString') then
FilteredLines.Add(Line);
RichEdit1.Lines.Assign(FilteredLines);
finally
FilteredLines.Free;
end;
end;
Upvotes: 0