如何在 RichEdit 中仅突出显示包含 'MyString' 的行?

How to highlight only the lines contain the 'MyString' in a RichEdit?

我创建了一个读取文本文件的小程序。

在 RichEdit 中打开文本文件后,我想更改包含特定字符串的行的背景颜色,或隐藏所有不包含该字符串的行。 可能吗?

我已经尝试搜索字符串,但我不知道如何执行我要求的操作。

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;

这是一个糟糕的 SO 问题,因为它有点像“请为我编写代码”。

自然的方法是找到问题的独立部分:

  1. 如何在Delphi中表示字符串数组(行)?

  2. 如何将 Delphi 中的文本文件加载到一些 in-memory 字符串数组中?

  3. 如何在Delphi的字符串中搜索子串?

  4. 如何过滤 Delphi in-memory 字符串数组? [如果您知道 1 并且听说过循环,那么这很简单。高效地做起来更有趣。]

  5. 如何填充 Delphi TRichEdit 控件?

的确,如果您知道 1--5 的答案,那么做您想做的事就很简单了!

我现在可能看起来像一个脾气暴躁的老人,但我认为我确实有一个关于如何处理编程问题的非常重要的观点。

无论如何,让我们一次解决一个问题:

  1. array of string 的 old-school 方法,今天写成 TArray<string> 有效。这是一个动态的字符串数组。由于 Delphi 动态数组由编译器管理,它们很方便,因为您不需要手动创建和释放它们。但是,它们有点 low-level 并且有时会被误用。

    可能更好的选择是使用 TStringList class.

  2. IOUtils 中,您会发现 TFile.ReadAllLines 将文件名和 returns(文本)文件的内容作为字符串数组。

    如果您有 TStringList,请使用 TStringList.LoadFromFile

  3. 传统上,您会使用 Pos 函数。但是今天你可以使用 string 助手:MyString.Contains()。显然,您需要决定是否要将大写字母和小写字母视为相同。

  4. 根据 3.

    中的测试,使用简单的 forfor in 循环从原始数组填充第二个数组
  5. 如果你有 TStringList,只需使用 TRichEdit.Lines.Assign

将它们放在一起,使用 string 数组和 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;

搜索和过滤文本然后将其放入 RichEdit 是最好的。

但是,如果文本已经加载到 RichEdit 中,TRichEdit 确实有一个可以使用的 FindText() 方法,您不应该搜索它的 Text 属性 手动。例如:

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;

也就是说,设置线条的背景颜色或删除线条(没有“隐藏”线条的选项)非常简单。

给定任何字符索引,您可以向 RichEdit 发送 EM_LINEFROMCHAR 消息以确定该字符出现的行索引。

然后您可以使用 TRichEdit.Lines.Delete() 方法从 RichEdit 中删除该行。

设置线条的背景颜色需要几个步骤:

  • 发送 RichEdit EM_LINEINDEX and EM_LINELENGTH 消息以确定行的开始和结束字符索引。

  • 设置 RichEdit 的 SelStartSelLength 属性(或向 RichEdit 发送 EM_EXSETSEL 消息)。

  • 向 RichEdit 发送一条 EM_SETCHARFORMAT message, specifying the SCF_SELECTION flag and using the CHARFORMAT2 记录,以设置所选内容的背景颜色。