从 RTF 文件中提取纯文本的函数给出了错误的结果

Function to extract plain text from RTF file gives wrong result

在 Windows 10 in Delphi 11 Alexandria 中的 32 位 VCL 应用程序中,我需要在 RTF 文件中搜索文本。所以我使用这个函数(发现here)从RTF文件中提取纯文本:

function RtfToText(const RTF_FilePath: string; ReplaceLineFeedWithSpace: Boolean): string;
var
  RTFConverter: TRichEdit;
  MyStringStream: TStringStream;
begin
  RTFConverter := TRichEdit.CreateParented(HWND_MESSAGE);
  try
    MyStringStream := TStringStream.Create(RTF_FilePath);
    try
      RTFConverter.Lines.LoadFromStream(MyStringStream);
      RTFConverter.PlainText := True;
      RTFConverter.Lines.StrictDelimiter := True;
      if ReplaceLineFeedWithSpace then
        RTFConverter.Lines.Delimiter := ' '
      else
        RTFConverter.Lines.Delimiter := #13;
      Result := RTFConverter.Lines.DelimitedText;
    finally
      MyStringStream.Free;
    end;
  finally
    RTFConverter.Free;
  end;
end;

但是,函数返回的不是 RTF 文件的纯文本内容,而是 RTF 文件的文件路径!

这个函数有什么问题,我怎样才能有效地从 RTF 文件中提取纯文本而不必使用父级 TRichEdit 控件?

Q 中的函数将 RTF 文件路径字符串直接分配给 TStringStream,而不加载 RTF 文件(正如@Remy Lebeau 正确观察到的:“TStringStream 构造函数不加载文件”)。

这是将 RTF 文件加载到 TStringStream:

的工作原理
function RtfToText(const RTF_FilePath: string; ReplaceLineFeedWithSpace: Boolean): string;
var
  RTFConverter: TRichEdit;
  MyStringStream: TStringStream;
begin
  RTFConverter := TRichEdit.CreateParented(HWND_MESSAGE);
  try
    MyStringStream := TStringStream.Create('');
    try
      MyStringStream.LoadFromFile(RTF_FilePath);
      RTFConverter.Lines.LoadFromStream(MyStringStream);
      RTFConverter.PlainText := True;
      RTFConverter.Lines.StrictDelimiter := True;
      if ReplaceLineFeedWithSpace then
        RTFConverter.Lines.Delimiter := ' '
      else
        RTFConverter.Lines.Delimiter := #13;
      Result := RTFConverter.Lines.DelimitedText;
    finally
      MyStringStream.Free;
    end;
  finally
    RTFConverter.Free;
  end;
end;

TStringStream 构造函数不会像您期望的那样加载文件。 TStringStream 不是 TFileStream。顾名思义,TStringStreamstring 的流包装器。因此,它的构造函数接收一个字符串并将其 as-is 复制到流中。因此,您正在使用文件路径字符串本身的值加载 RichEdit,而不是该字符串引用的文件的内容。

你实际上根本不需要 TStringStream,因为 TRichEdit 可以直接加载文件,例如:

function RtfToText(const RTF_FilePath: string; ReplaceLineFeedWithSpace: Boolean): string;
var
  RTFConverter: TRichEdit;
begin
  RTFConverter := TRichEdit.CreateParented(HWND_MESSAGE);
  try
    RTFConverter.PlainText := False; 
    RTFConverter.Lines.LoadFromFile(RTF_FilePath);
    RTFConverter.PlainText := True;
    RTFConverter.Lines.StrictDelimiter := True;
    if ReplaceLineFeedWithSpace then
      RTFConverter.Lines.Delimiter := ' '
    else
      RTFConverter.Lines.Delimiter := #13;
    Result := RTFConverter.Lines.DelimitedText;
  finally
    RTFConverter.Free;
  end;
end;

也就是说,除了 TRichEdit 之外,在原生 RTL 或 VCL 中没有任何东西可以为您将 RTF 解析为 plain-text。如果您不想使用 TRichEdit,您将不得不自己解析 RTF,或者寻找第三方解析器来使用。