Невозможно удалить "нулевые символы" из строки
Я задавал подобный вопрос пару месяцев назад. Благодаря 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;
Я преобразовал TMemorystream
в string
удалять Null Chars
с StringReplace()
а затем преобразовал его снова в TStringstream
загрузить его Richedit.lines.LoadFromStream
,
Но моя проблема в том, что я не могу удалить Null Character
с помощью StringReplace()
, Я могу заменить другие символы, но не #0
,
Есть ли способ удалить нулевые символы прямо в TMemorystream
и загрузить его в Richedit
? Как? Если это невозможно или очень сложно, как я могу удалить их, когда преобразую текст в string
?
Благодарю.
2 ответа
Насколько я вижу, все утилиты поиска / замены, в тот или иной момент, приводят входные данные к 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);
Замена в потоке также будет включать в себя тестирование каждого символа, а затем настройку потока соответствующим образом, прежде чем двигаться дальше после того, как вы решите удалить его.
Ответ Сертака точен, и вы должны принять его. Если производительность важна, и у вас есть большая строка с частыми экземплярами нулевого символа, вам следует попытаться уменьшить количество выделений кучи. Вот как я бы это реализовал:
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;