Så nu har jeg en version der virker. Der er lavet en del om. Det hele er trukket ud i en ny procedure, og algoritmen er ændret lidt. Men det går stærkt.
Hvis du ikke forstår koden helt må du spørge. Sådan noget optimeret kode er ikke ret nemt at læse, secielt fordi der bliver brugte nogle beskidte tricks i den :-)
Her er koden :
//du bad om noget fart så skal vi lige bruge en ny procedure
//til at finde længden af en Pchar : (omkring 8 gange hurtigere end StrLen)
function StrLenASM(tStr:PChar):integer;
asm
MOV EDX,7
ADD EDX,EAX
PUSH EBX
MOV EBX,[EAX]
ADD EAX,4
@L1: LEA ECX,[EBX-$01010101]
XOR EBX,-1
AND ECX,EBX
MOV EBX,[EAX]
ADD EAX,4
AND ECX,80808080H
JZ @L1
TEST ECX,00008080H
JNZ @L2
SHR ECX,16
ADD EAX,2
@L2: SHL CL,1
POP EBX
SBB EAX,EDX
end;
procedure TForm1.DoTheTrick(StringList : TStringList; Start : Integer = 0);
//StringList er en buffer vi bruger til at stoppe den blok af teksen over i som
//senere skal gemmes i en fil. Frodelen ved at overføre den som arameter er at den
//ikke skal oprettes og nedlægges hver gang.
//Start er en Index for hvor i listen vi skal starte vores søgning.
var
i,j,k : Integer;
p : PChar;
stop : Integer;
span : Integer;
begin
i:= Start;
j:= RichEdit1.Lines.Count;
repeat //Hurtigere løkke struktur end for sætninger
with RichEdit1 do
begin
p:= pointer(Lines[i]);
//Hvis du overstyrer en String til en pointer, få du adgang direkte til
//de bogstaver strengen består af der hvor de ligger.
//Det har samme efekt som at overstyre det
if (bool(p)) and (p[0] = \'O\') then
break; //grimt hack
inc(i);
end;
until i >= j;
// Når vi er nået her så ved vi følgende :
// Hvis i = j så fandt vi ingen ting --> Exit proceduren eller
// Hvis i > j så er vi rendt ud over enden af vores liste --> Exit proceduren
// Ellers Nåede vi aldrig enden af dokumentet og har dermed fundet vores start linje
// da vores break er sat ind INDEN vi tæller i op ved vi at i er vores start linje.
if i < j then
start := i
else
exit;
repeat //Hurtigere løkke struktur end for sætninger
with RichEdit1 do
begin
p:= pointer(Lines[i]);
if (bool(p)) then //Meget grimt hack men hurtigere end if p <> nil
begin
k := StrlenASM(p) -1;
if (p[k] = \'#\') or (p[k] = \'%\') then
break; //grimt hack.
end;
inc(i);
end;
until i > j;
// Når vi er nået her så ved vi følgende :
// Hvis i >j så fandt vi ingen ting --> Exit proceduren
// Ellers Nåede vi aldrig enden af dokumentet og har dermed fundet vores stop linje
// da vores break er sat ind INDEN vi tæller i op ved vi at i er vores stop linje.
if j>i then
stop := i
else
exit;
// Vi er nået forbi vores exit komando ergo har vi fundet både start og stop
//Ryd vores buffer
StringList.Clear;
//Nulstil vores Index
k := 0;
//Beregn antal linjer der skal kopieres
span := stop-start;
repeat
p:= pointer(RichEdit1.Lines[start+k]);
StringList.Insert(k,p);
//Ved at kalde Insert og ikke Add sparer vi et procedure kald
//Vi har kaldt en clear på vores StringList derfor ved vi at antallet af linjer
//til en hvertid er det samme som k. Ergo sparer vi et kald til getCount.
//getCount er en protected procedure der retunerer antallet af linjer på en TStrings;
inc(k);
until k > span;
p := @RichEdit1.Lines[start][2];
//Smid det første 0 væk
//Igen et grimt hack, men det virker :-)
//Dette er en beregning vi skal bruge flere gange kan der spares
//ved at stoppe det over i en variabel
k:= Start+span;
//Hvis vi er ved den sidste blok .. Så ryd op efter os selv
if k = j-1 then
begin
RichEdit1.Lines.Delete(k);
StringList.Delete(span);
end;
StringList.SaveToFile(p+\'.txt\');
DoTheTrick(StringList,Stop+1);
//Vi kalder os selv igen med vores Stop+1 fordi vi skal fortsætte søgningen
//Fra tidligst fra næste linje, i froholt til vores stop linje fra før.
end;
procedure TForm1.Button1Click(Sender: TObject);
var
StringList : TStringList;
p : PChar;
k,j : Integer;
begin
j:= RichEdit1.Lines.Count;
p:= pointer(RichEdit1.Lines[j-1]);
k := StrlenASM(p) -1;
//Hvis vores tekst ikke er termineret \"ordenligt\" simder vi selv
//en terminator på. Det har den fordel at vi ikke hele tiden skal teste
//for om vi er nået enden, men det i mod vi kan koncentrerer os om at finde
//den næste terminator. Og der af følgende hvis vi ingen finder så stop
//vores rekusion
if (p[k] <> \'#\') and (p[k] <> \'%\') then
RichEdit1.Lines.add(\'%\');
StringList := TStringList.Create;
DoTheTrick(StringList);
StringList.Free;
end;
Jens B
http://fotx.net/borrisholtOrv ja Lad mig lige slå et slag for at Delphi grupper bliver godt repræsenteret ved Eksperten festen (
http://www.ekspertenfest.dk)