2013-09-14 3 views
3

пару месяцев назад я попросил аналогичный question. Благодаря 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.

Есть ли способ удалить нулевые charcters непосредственно в TMemorystream и загрузить его в Richedit? Как? Если это невозможно или это очень сложно, как я могу удалить их, когда я конвертирую свой текст в string?

Спасибо.

+1

1) вход один символ 2) если он это не 'NUL', а затем вывести его, иначе отбросить его 3) перейдите к шагу 1. –

+1

Почему вы приняли мой ответ раньше, если он не сработал? Обратите внимание, что я обновил свой ответ, чтобы упомянуть о недостатке «StringReplace» и ссылку на [другой ответ] (http://stackoverflow.com/a/3685055/33732), который выполняет ту же задачу. –

+3

Реальный вопрос: почему у файла есть нули в нем для начала? Текстовый файл с кодировкой UTF-8 не должен иметь никаких нулей, поэтому файл, скорее всего, не UTF-8. И этот код ужасно неэффективен для всех конверсий UTF8-> UTF16-> UTF8-> UTF16. –

ответ

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); 

Замена в потоке так же будет связан с тестированием каждого символа, а затем регулировать поток соответственно, прежде чем перейти после того, как вы решите удалить один.

+1

Вы можете быть в своем ответе, указать, что «delete» следует использовать только с небольшим количеством данных. [compare delete vs others] (http://stackoverflow.com/questions/18460211/making-a-character-variable-equal-to-a-nill-value-in-delphi) –

+0

@ moskito - Казалось бы, да. ИМО, однако, объясняет причину и дает простой пример. –

+0

@ Сertac Я думаю, что так должно быть. К сожалению, реальность такова, что люди, которые не знают ничего лучшего, будут слепо использовать любой код, который вы публикуете. Утверждение об отказе от ответственности: «Не используйте этот код в производстве, так как он разбивает кучу», было бы достаточно для меня. Даже тогда, несмотря на то, что я много людей, вы игнорируете предупреждение! –

7

Ответ Сертака является точным, и вы должны его принять. Если производительность важна, и у вас есть большая строка с частыми экземплярами нулевого символа, вы должны попытаться уменьшить количество распределений кучи. Вот как я бы это реализовать:

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; 
+0

@Sky Я бы предпочел, если бы вы приняли ответ Сертака. –

+0

Хорошо. Принял ответ Сертака :) – Sky

Смежные вопросы