Results 1 to 1 of 1

Thread: Snel een deel van een string vervangen

  1. #1
    Senior Member PsychoMark's Avatar
    Join Date
    Nov 2001
    Location
    Raamsdonksveer
    Posts
    10,269

    Snel een deel van een string vervangen

    Omschrijving

    Nee, dit gaat niet over een StringReplace vervanger, daar is FastStrings al voor, dit gaat over een ander scenario:


    Voor een applicatie moest ik de mogelijkheid hebben om uit een string een gedeelte te vervangen door een andere string. De startpositie en lengte van de te vervangen string waren in dat geval al bekend, dus StringReplace was een beetje onzinnig...

    De standaard techniek hiervoor is om de Copy() functie te gebruiken om de string in 2en te splitsen en het nieuwe stuk er in te plakken, echter, uit ervaring weet ik dat Copy() elke keer een nieuwe string instantie aanmaakt, wat dus relatief veel geheugen en ook snelheid kost bij grotere strings, ik begon dus te denken of dat niet taktischer kon, en ben uiteindelijk tot de onderstaande code gekomen.


    De test-code zit er bij, op een P550 met 64 MB RAM gaf dit als overtuigend resultaat:

    Testing 100.000 iterations - ReplacePart
    Time taken: 24,384 second(s)
    Testing 100.000 iterations - FastReplacePart
    Time taken: 2,0613 second(s)

    ...12 keer sneller, is naar mijn idee toch zeker de moeite waard . De tests zijn niet uitgebreid herhaald met veel verschillende situaties, en de uitkomst varieerde van 9 tot 13 keer zo snel, waarbij de FastReplacePart functie echter redelijk stabiel bleef hangen rond de 2 seconden. Feit blijft: de functie is sneller, veeeeel sneller.


    Opmerkingen

    Wederom bedankt voor deze tip SVG: voor de mensen die proberen dit gewoon in een unit te plakken, dat kan, mits je de functies eruit filterd. Als je het gehele testpakket wilt proberen, maak dan een nieuwe console applicatie aan (File -> New -> Console Application), vervang de code die je daarna in beeld krijgt door de onderstaande code en sla het project op onder de naam 'StringReplace' (aangezien bovenaan het bestand al staat "program StringReplace" ).



    Code

    Code:
    program StringReplace;
    
    {$APPTYPE CONSOLE}
    
    uses
      Windows,
      SysUtils,
      Math;
    
    {
      Deze functies zijn toegevoegd om de tijd te kunnen meten die een bepaald
      stukje code nodig heeft om uit te voeren. De Math unit is dan ook enkel nodig
      voor TimeStop() (om de tijd weer te geven mbv RoundTo), dus indien je gebruik
      maakt van Delphi versies die deze functie niet heeft, haal RoundTo weg en
      verwijder de Math unit. Op het NLDelphi forum staat eventueel een vervanger
      voor de RoundTo functie, zoek even op, jawel, 'RoundTo' :)
    }
    var
      GFreq:      Int64;
      GTimer:     Int64;
    
    procedure TimeInit();
    begin
      QueryPerformanceFrequency(GFreq);
    end;
    
    procedure TimeStart();
    begin
      QueryPerformanceCounter(GTimer);
    end;
    
    procedure TimeStop();
    var
      iEnd:       Int64;
    
    begin
      QueryPerformanceCounter(iEnd);
      Dec(iEnd, GTimer);
      WriteLn('Time taken: ', FloatToStr(RoundTo(iEnd / GFreq, -4)),
              ' second(s)');
      GTimer  := 0;
    end;
    
    
    {
      Hier de functies die het echt werk doen, zowel op de traditionele als mijn
      eigen wijze...
    }
    function ReplacePart(const ASource: String; const AStart, ALength: Integer;
                         const AReplace: String): String;
    begin
      Result  := Copy(ASource, 1, AStart - 1) + AReplace +
                 Copy(ASource, AStart + ALength, MaxInt);
    end;
    
    function FastReplacePart(const ASource: String; const AStart, ALength: Integer;
                             const AReplace: String): String;
    var
      iSrcLength: Integer;
      iLength:    Integer;
      iDiff:      Integer;
      iDest:      Integer;
    
    begin
      iSrcLength  := Length(ASource);
      iLength     := Length(AReplace);
      iDiff       := iLength - ALength;
      iDest       := 1;
    
      SetLength(Result, iSrcLength + iDiff);
    
      // Write first part
      CopyMemory(@Result[iDest], @ASource[1], AStart - 1);
      Inc(iDest, AStart - 1);
    
      // Write replacement
      CopyMemory(@Result[iDest], @AReplace[1], iLength);
      Inc(iDest, iLength);
    
      // Write last part
      CopyMemory(@Result[iDest], @ASource[AStart + ALength],
                 iSrcLength - AStart - (ALength - 1));
    end;
    
    
    {
      Hier de test-code die gebruikt is om te bepalen of het allemaal wel zin
      heeft. Er is expres gekozen voor een redelijke string (10.000 bytes) om de
      functies een beetje te stresstesten.
    }
    var
      sTest:      String;
      sReplace:   String;
      iLoop:      Integer;
    
    begin
      { Als je wilt testen of de functies echt werken:
      WriteLn(ReplacePart('Dit was een test!', 5, 3, 'is'));
      WriteLn(FastReplacePart('Dit was een test!', 5, 3, 'is'));
      ReadLn;
      exit;
      }
    
      TimeInit();
    
      sTest     := StringOfChar('X', 10000);
      sReplace  := StringOfChar('Y', 200);
    
      WriteLn('Testing 100.000 iterations - ReplacePart');
      TimeStart();
      for iLoop := 0 to 99999 do
        ReplacePart(sTest, 5, 10, sReplace);
      TimeStop();
    
      WriteLn('Testing 100.000 iterations - FastReplacePart');
      TimeStart();
      for iLoop := 0 to 99999 do
        FastReplacePart(sTest, 5, 10, sReplace);
      TimeStop();
    
      ReadLn;
    end.
    Last edited by PsychoMark; 07-Nov-02 at 14:52.
    Qui custodiet ipsos custodes

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •