4

几个月前我问了一个类似的问题。感谢Rob Kennedy,我可以将我的整个文本加载到一个Richedit 但我无法删除Null chars的 . 我可以加载我的文本,因为我使用了Stream.


现在在这段代码中:

var
  strm : TMemorystream;
  str  : UTF8string;
  ss   : TStringstream;

begin
  strm := tmemorystream.Create;

  try
    strm.LoadFromFile('C:\Text.txt');
    setstring(str,PAnsichar(strm.Memory),strm.Size);
    str := StringReplace(str, #0, '', [rfReplaceAll]);  //This line doesn't work at all
    ss  := tstringstream.Create(str);
    Richedit1.Lines.LoadFromStream(ss);
  finally
    strm.Free;
    ss.Free;
  end;
end;

我转换TMemorystreamstring删除Null CharsStringReplace()然后再次转换TStringstream为加载它Richedit.lines.LoadFromStream

但我的问题是我无法删除Null Characterusing StringReplace()。我可以替换其他字符,但不能#0

有什么方法可以直接删除空字符TMemorystream并将其加载到Richedit? 如何?如果不可能或非常复杂,当我将文本转换为 时如何删除它们string

谢谢。

4

2 回答 2

10

Sertac 的回答是准确的,您应该接受它。如果性能很重要,并且您有一个带有频繁空字符实例的大字符串,那么您应该尝试减少堆分配的数量。以下是我将如何实现它:

function RemoveNull(const Input: string): string;
var
  OutputLen, Index: Integer;
  C: Char;
begin
  SetLength(Result, Length(Input));
  OutputLen := 0;
  for Index := 1 to Length(Input) do
  begin
    C := Input[Index];   
    if C <> #0 then
    begin
      inc(OutputLen);
      Result[OutputLen] := C;
    end;
  end;
  SetLength(Result, OutputLen);
end;

如果你想直接在内存流中做,那么你可以这样做:

procedure RemoveNullFromMemoryStream(Stream: TMemoryStream);
var
  i: Integer;
  pIn, pOut: PByte;
begin
  pIn := Stream.Memory;
  pOut := pIn;
  for i := 0 to Stream.Size-1 do
  begin
    if pIn^ <> 0 then
    begin
      pOut^ := pIn^;
      inc(pOut);
    end;
    inc(pIn);
  end;
  Stream.SetSize(NativeUInt(pOut)-NativeUInt(Stream.Memory));
end;
于 2013-09-14T13:24:48.537 回答
8

据我所见,所有搜索/替换实用程序有时都会将输入转换为 PChar,其中“#0”是终止字符。因此,它们永远不会超过第一个 Null 之前的字符串部分。您可能需要设计自己的机制。只是一个简单的例子:

var
  i: Integer;
begin
  Assert(str <> '');
  i := 1;
  while i <= Length(str) do
    if str[i] = #0 then
      Delete(str, i, 1)
    else
      Inc(i);

在流中替换同样涉及测试每个字符,然后在您决定删除一个字符后继续之前相应地调整流。

于 2013-09-14T13:09:23.563 回答