Lazarus (FPC) vs Java

0

Hej! Pewnie takich porównań było już dużo, ale czy ktoś ma doświadczenie z Lazarusem w połączeniu z bazami danych? Czy to lepiej funkcjonuje niż Java + Appache Derby? Lazarus przypomina bardzo Delphi i C++ Buildera i widzę ciekawe komponenty bazodanowe, tylko pytanie jak to realnie działa?
P.S. Z ciekawości przerobiłem taki programik z Javy do Lazarusa i okazało się że np. program w Javie tą samą operacje wykonuje 6 sekund, a wersja napisana w Lazarusie 2,5 sekundy...

0

A kod napisany w c plus wykonuje się około 20 razy szybciej.. To sprawka przenosnosci kodu itd. pomimo tego wolałbym javę.. Lazarus to padaka.

0

Będę mieć chwilę czasu to przerobie kod na C++ (biblioteka wxWidgets) i na C# Podejrzewam, że C# będzie trochę szybszy od Javy, a C++ najszybszy

0

Kilka uwag:

  1. Na Ubuntu Java lata sporo szybciej niż Mono: Ubuntu 32-bit Core 2 Quad Ubuntu 64-bit Core 2 Quad
  2. H2 Database powinno być ok 2x szybsze niż Apache Derby: http://www.h2database.com/html/performance.html
  3. GUI w Javie możesz spróbować zaklepać w JavieFX 2.0 - jest wtyczka (do NetBeansa przynajmniej) dodająca wsparcie dla tej wersji JavyFX
  4. Musiałeś skopać implementację w Javie, wątpliwe by kod Pascalowy był szybszy od Javowego (tzn porównujemy kompilatory/ maszyny wirtualne)
0

Jakiej bazy danych użyłeś w przypadku Lazarusa i w przypadku Javy? Tej samej czy czegoś innego?
Baza danych to najczęściej wąskie gardło aplikacji, więc jeżeli użyłeś różnych baz danych to raczej to jest główna przyczyna w różnicach w wydajności.

0

Tzn. akurat ten program to nie jest typowo bazodanowy...
Kod zamieniający znaki w plikach :

 
procedure TForm1.Zamien_BitBtnClick(Sender: TObject);
var PlikWejsciowy, PlikWyjsciowy : TextFile;
var TekstZPliku, WczytanyTekst, TekstPoZmianach : string;
var czas1, czas2 : Int64;
begin
  czas1 := GetMsCount;
  Zamien_BitBtn.Enabled := false;
  Application.ProcessMessages;
  Screen.Cursor := crHourGlass;
  Application.ProcessMessages;
  TekstPoZmianach:='';
  TekstZPliku := '';
  if ((PlikWejsciowy_Edit.Text <> '') and (PlikWyjsciowy_Edit.Text <> ''))  then
  begin
          AssignFile(PlikWejsciowy, PlikWejsciowy_Edit.Text);
          Reset(PlikWejsciowy);
          while not (EOF(PlikWejsciowy)) do
          begin
               ReadLn(PlikWejsciowy, WczytanyTekst);
               TekstZPliku := TekstZPliku + WczytanyTekst + #13+#10;
          end;
          CloseFile(PlikWejsciowy);
          TekstPoZmianach := StringReplace(TekstZPliku, ZnakDoZnalezienia1_Edit.Text, ZnakDoZamiany1_Edit.Text, [rfReplaceAll]);
          TekstPoZmianach := StringReplace(TekstPoZmianach, ZnakDoZnalezienia2_Edit.Text, ZnakDoZamiany2_Edit.Text, [rfReplaceAll]);
  end;

  AssignFile(PlikWyjsciowy, PlikWyjsciowy_Edit.Text);
  Rewrite(PlikWyjsciowy);
  Write(PlikWyjsciowy, TekstPoZmianach);
  Flush(PlikWyjsciowy);
  CloseFile(PlikWyjsciowy);
  Zamien_BitBtn.Enabled := true;
  Application.ProcessMessages;
  Screen.Cursor := crDefault;
  Application.ProcessMessages;
  czas2 := GetMsCount;
  ShowMessage('Zamiany dokonano w czasie : ' + IntToStr(czas2-czas1) + ' ms'); 

Kod java :

/**
 * Funkcja zamieniająca podany łańcuch znaków na inny
 * @param builder łańcuch (ciąg) znaków, w którym będzie zamiana
 * @param from łańcuch (ciąg) znaków, który jest poszukiwany do zamiany
 * @param to łańcuch (ciąg) znaków, na który ma być zamieniony
 */
public static void replaceAll(StringBuilder builder, String from, String to)
{
    int index = builder.indexOf(from);
    while (index != -1)
    {
        builder.replace(index, index + from.length(), to);
        index += to.length(); // Move to the end of the replacement
        index = builder.indexOf(from, index);
    }

public class ZamianaTekstu_Watek extends Thread {
    public void run() {
        // Spradzamy czy wprowadzono ścieżkę i nazwę pliku
        // Jeśli nie to jest wyświetlany komunikat
        if ((PlikWejsciowy_jTextField.getText().equals("") == true) || (PlikWyjsciowy_jTextField.getText().equals("") == true))
        {
            JOptionPane.showMessageDialog(null, "Proszę wybrać plik wejściowy i wyjściowy! ", "Ostrzeżenie", JOptionPane.WARNING_MESSAGE);           
        } // jeśli wprowadzonn nazwy plików
        else
        {
        // ustaw klepsydrę jako kursor
        Cursor hourglassCursor = new Cursor(Cursor.WAIT_CURSOR);
        setCursor(hourglassCursor);
        // odśmiecamy pamieć tj. wymuszenie uruchomienia Garbage Collectora
          System.gc();
          long start,koniec,czas;
           start = java.lang.System.currentTimeMillis(); // bieżący czas w ms

        {
         try
             {
              // otwieramy plik - nazwa pliku jest już w kontrolce GUI TextField
             File file = new File(PlikWejsciowy_jTextField.getText());
             // przygytowanie do odczytu
             BufferedReader reader = new BufferedReader(new FileReader(file));
             String line = "";
             String oldtext = "";
             // w pętli odczytujemy linijka po linijce do końca pliku
             while((line = reader.readLine()) != null)
                 {
                 oldtext += line + "\r\n";
             }
             reader.close(); // zamykamy strumień
             // w celu szybszego działania zamianu używamk klasy StringBuilder
            StringBuilder sb_oldtext = new StringBuilder(oldtext); 
            // zamiana (funkcja do operacji na StringBuilder)
            replaceAll(sb_oldtext, ZnakiDoZnalezienia1_jTextField.getText(), ZnakiDoZamiany1_jTextField.getText()); 
            replaceAll(sb_oldtext,ZnakiDoZnalezienia2_jTextField.getText(), ZnakiDoZamiany2_jTextField.getText());  
            // zapis do pliku 
            FileWriter writer = new FileWriter(PlikWyjsciowy_jTextField.getText());
            writer.write(sb_oldtext.toString());
            // zapizs bufor
            writer.flush();
            // zamknięcie uchwytu pliku
            writer.close();

         }
         catch (IOException ioe)
             {
              JOptionPane.showMessageDialog(null, ioe.toString(), "Błąd", JOptionPane.ERROR_MESSAGE);

         }
     }
        // przywracamy kursor
        Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
        setCursor(normalCursor);
        koniec = java.lang.System.currentTimeMillis(); // bieżący czas w ms
        czas = koniec - start;//czas działań w ms
        double czas_w_sekundach = czas / 1000;
        double czas_w_minutach = czas_w_sekundach / 60;
             JOptionPane.showMessageDialog(null, "Dokonano zamiany w czasie  " + String.format("%.0f", czas_w_sekundach)                  
                + " sekund" + "( "+ Double.toString(czas_w_minutach) + " minut)" , "Komunikat", JOptionPane.INFORMATION_MESSAGE);
        // zamknięcie okna dialogowego z komunikatem o oczekiwaniu i animacją
        // wcześniej okno zostało pokazane przed wejściem w ten wątek
        OknoOczekiwaniaDialog.setVisible(false);
        }
 
1

Ten fragment jest wyjątkowo źle napisany

             String oldtext = "";
             // w pętli odczytujemy linijka po linijce do końca pliku
             while((line = reader.readLine()) != null)
                 {
                 oldtext += line + "\r\n";
             }

Zmienna oldtext winna być typu StringBuilder lub StringBuffer.

0
  1. Użyj String.replaceAll() zamiast tej swojej funkcji replaceAll()
  2. W pętli while dalej używasz konkatenacji Stringów zamiast StringBuildera.
  3. Po co w ogóle ładować wszystko naraz, skoro można odczytywać te linie pojedynczo, modyfikować i od razu zapisywać?
0

String.ReplaceAll działa w przypadku tylko stringa, nie działa w przypadku StringBuffer lub StringBuilder... Tzn, nie ma takiego samego zaczenia co String.ReplaceAll... Stąd ten własny kod.
Hmm jak chce zmienic na :

             StringBuilder line = "";
             StringBuilder oldtext = "";
             // w pętli odczytujemy linijka po linijce do końca pliku
             while((line = reader.readLine()) != null)
                 {
                 oldtext += line + "\r\n";
             }

to kompilator rzuca błedy niezgodnosci typow.... :/

Niemniej moim skromnym zdaniem ObjectPascal jakiś bardziej przejrzysty mi się wydaje i bardziej "humanistyczny" niż Java...

0

Przy takiej znajomości i rozumieniu Javy nie powinieneś się wypowiadać na jej temat.

             String line = "";
             StringBuilder oldtext = new StringBuilder("");
             // w pętli odczytujemy linijka po linijce do końca pliku
             while((line = reader.readLine()) != null)
                 {
                 oldtext.append(line + "\r\n");
             }
0
bo napisał(a)

Przy takiej znajomości i rozumieniu Javy nie powinieneś się wypowiadać na jej temat.

             String line = "";
             StringBuilder oldtext = new StringBuilder("");
             // w pętli odczytujemy linijka po linijce do końca pliku
             while((line = reader.readLine()) != null)
                 {
                 oldtext.append(line + "\r\n");
             }

Aaaa.. dzieki :)

Po zmianach znów zrobie porównianie...
Zmieniłem kod... No teraz po kilku próbach program w Javie okazał... się minimalnie szybszy niż ten skompilowany w FPC :)
Czyli przekonałem się na własnej skórze, ile zależy od umiejętności wykorzystania języka...
:)
Będę mieć chwilę czasu przepisze kod na C/C++

0

Na mojej maszynie stosunek czasów wykonania poniższych funkcji

    String s="A";
    int ile=100000;
    String powiel1(String s,int ile)
    {
        String zwrot="";
        for (int i=1;i<=ile;i++)
        {
            zwrot+=s;
        }
        return zwrot;
    }
    String powiel2(String s,int ile)
    {
        StringBuffer zwrot=new StringBuffer("");
        for (int i=1;i<=ile;i++)
        {
            zwrot.append(s);
        }
        return new String(zwrot);
    }

wynosi około 7000.

0

Na mojej maszynie stosunek czasów wykonania poniższych funkcji
...
wynosi około 7000.

Nikt nie powiedział więc może dopowiem żeby nikt nie wyciągnął błędnych wniosków. Ta różnica wynika nie z tego że konkatenacja stringów w Javie jest taka wolna, ale z ich niezmienności.
To znaczy że 100000 wywołanie str += "a"; Powoduje utworzenie 100000 instancji Stringa. Inaczej mówiąc, w pamięci będą siedziały napisy "a", "aa", "aaa", "aaaa" i tak aż do "a" * 100000 z czego używany będzie tylko ten ostatni.

0

String.ReplaceAll działa w przypadku tylko stringa, nie działa w przypadku StringBuffer lub StringBuilder... Tzn, nie ma takiego samego zaczenia co String.ReplaceAll... Stąd ten własny kod.

To jakie ma znaczenie? Jedyna różnica to taka, że String.replaceAll() traktuje parametry jako regexy, ale przecież możesz sobie wyescapować znaki kontrolne.

public class Main {

    public static void replaceAll(StringBuilder builder, String from, String to) {
        int index = builder.indexOf(from);
        while (index != -1) {
            builder.replace(index, index + from.length(), to);
            index += to.length(); // Move to the end of the replacement
            index = builder.indexOf(from, index);
        }
    }

    void run() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 123456; i++) {
            sb.append(i);
        }
        long time1 = System.currentTimeMillis();
        String wynik1 = sb.toString().replaceAll("1", "2").substring(5, 15);
        System.out.printf("Czas: %8d " + wynik1 + "\n", System.currentTimeMillis() - time1);
        long time2 = System.currentTimeMillis();
        replaceAll(sb, "1", "2");
        String wynik2 = sb.toString().substring(5, 15);
        System.out.printf("Czas: %8d " + wynik2 + "\n", System.currentTimeMillis() - time2);
    }

    public static void main(String[] args) {
        new Main().run();
    }
}

Daje taki wynik:

run:
Czas:       65 5678920222
Czas:    21021 5678920222
BUILD SUCCESSFUL (total time: 22 seconds)

Format wyniku: Czas w milisekundach + wycinek z wynikowego Stringa.

Wynikowy String jest taki sam, niestety twój kod się kwadraci. Dla 10x większego Stringa długość wykonania twojej procedury replaceAll rośnie 100x. String.replaceAll() jest za to liniowy.

Wniosek: w zależności od długości plików wejściowych twój program można przyspieszyć od kilkudziesięciu razy do kilkuset milionów razy.

0

Zainstalowałem Jave 1.7 SDK i najnowszego NetBeansa i przerobiłem projekt wg wskazówek...

 
public class ZamianaTekstu_Watek extends Thread {
    public void run() {
        // Spradzamy czy wprowadzono ścieżkę i nazwę pliku
        // Jeśli nie to jest wyświetlany komunikat

        if ((PlikWejsciowy_jTextField.getText().equals("") == true) || (PlikWyjsciowy_jTextField.getText().equals("") == true))
        {
            JOptionPane.showMessageDialog(null, "Proszę wybrać plik wejściowy i wyjściowy! ", "Ostrzeżenie", JOptionPane.WARNING_MESSAGE);           
        } // jeśli wprowadzono nazwy plików
        else
        {
        // ustaw klepsydrę jako kursor
        Cursor hourglassCursor = new Cursor(Cursor.WAIT_CURSOR);
        setCursor(hourglassCursor);
        // odśmiecamy pamieć tj. wymuszenie uruchomienia Garbage Collectora
          System.gc();
          long start,koniec,czas;
           start = java.lang.System.currentTimeMillis(); // bieżący czas w ms

        {
         try
             {
              // otwieramy plik - nazwa pliku jest już w kontrolce GUI TextField
             File file = new File(PlikWejsciowy_jTextField.getText());
             // przygytowanie do odczytu
             BufferedReader reader = new BufferedReader(new FileReader(file));
             String line = "";
             StringBuilder oldtext = new StringBuilder("");
             String TekstPoZmianach = "";
             // w pętli odczytujemy linijka po linijce do końca pliku
             while((line = reader.readLine()) != null)
                 {
                 line = line + "\r\n";
                 oldtext.append(line);
             }
             reader.close(); // zamykamy strumień
             // w celu szybszego działania zamiany używamy klasy StringBuilder
            StringBuilder sb_oldtext = new StringBuilder(oldtext); 
            // zamiana (funkcja do operacji na StringBuilder)
            TekstPoZmianach = sb_oldtext.toString().replace(ZnakiDoZnalezienia1_jTextField.getText(), ZnakiDoZamiany1_jTextField.getText());
            // dodatkowy obiekt typu StringBuilder w którym przechowujemy tekst po pierwszej zamianie
            StringBuilder sb_oldtext2 = new StringBuilder(TekstPoZmianach);
            // kolejna zamiana tekstu... 
            TekstPoZmianach = sb_oldtext2.toString().replace(ZnakiDoZnalezienia2_jTextField.getText(), ZnakiDoZamiany2_jTextField.getText());
            // zapis do pliku 
            FileWriter writer = new FileWriter(PlikWyjsciowy_jTextField.getText());
            //writer.write(sb_oldtext.toString());
            writer.write(TekstPoZmianach);
            // zapisz bufor
            writer.flush();
            // zamknięcie uchwytu pliku
            writer.close();

         }
         catch (IOException ioe)
             {
              JOptionPane.showMessageDialog(null, ioe.toString(), "Błąd", JOptionPane.ERROR_MESSAGE);

         }
     }
        // przywracamy kursor
        Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
        setCursor(normalCursor);
        koniec = java.lang.System.currentTimeMillis(); // bieżący czas w ms
        czas = koniec - start;//czas działań w ms
        double czas_w_sekundach = czas / 1000;
        double czas_w_minutach = czas_w_sekundach / 60;
             JOptionPane.showMessageDialog(null, "Dokonano zamiany w czasie  " + String.format("%.0f", czas_w_sekundach)                  
                + " sekund" + "( "+ Double.toString(czas_w_minutach) + " minut)" , "Komunikat", JOptionPane.INFORMATION_MESSAGE);
             System.gc();
        // zamknięcie okna dialogowego z komunikatem o oczekiwaniu i animacją
        // wcześniej okno zostało pokazane przed wejściem w ten wątek
        OknoOczekiwaniaDialog.setVisible(false);
        }


    }
}

Efekt jest taki, że plik 1 mb w programie skompilowany w Lazarusie (FPC) przetwarza się ok 5 minut, a w Javie 1 sekunde...
Ciekawe czy kod Pascala da się jakoś zoptymalizować....
Będę mięć czas to przepisze kod na C++ i C# (swoją drogą ciekawe czy będzie mieć znaczenie czy użyje w przypadku C++ biblioteki QT albo wxWidgets, skoro kompilator jest ten sam - MinGW).

0

Wszystko da się zoptymalizować. Kod w FPC nie powinien być dużo wolniejszy od Javowego, na pewno jeżeli jest więcej niż kilka razy wolniejszy to jest to wina kiepsko napisanego kodu. Podobnie jeżeli kod Javowy jest wolniejszy od C++owego więcej niż kilka razy to też zwykle jest to wina kiepsko napisanego kodu (rzadziej: innymi czynnikami, typu przebijanie się przez JNI czy JNA, lub niska ilość RAMu).

0
Wibowit napisał(a)

Wszystko da się zoptymalizować. Kod w FPC nie powinien być dużo wolniejszy od Javowego, na pewno jeżeli jest więcej niż kilka razy wolniejszy to jest to wina kiepsko napisanego kodu. Podobnie jeżeli kod Javowy jest wolniejszy od C++owego więcej niż kilka razy to też zwykle jest to wina kiepsko napisanego kodu (rzadziej: innymi czynnikami, typu przebijanie się przez JNI czy JNA, lub niska ilość RAMu).

Czyli tak na prawdę to wiele jest stereotypów typu, że programy w C++ z reguły są szybsze niż pisane w Javie albo C# ?
Kiedyś nawet uruchamiałem Quake2, który został napisany w Javie (przepisany z C++) i działał tak samo szybko jak ten w C++. Jednak javowa wersja Quake2 była uruchomiona na współczesnym (w miarę) procesorze, bo dwurdzeniowym itp.
Podejrzewam, że Quake 2 w wersji napisanej w Javie uruchomiony na komputerze z epoki kiedy się ta gra była nowością to, była by wolniejsza niż ta napisana w C++ ale przy obecnych sprzętach różnica szybkości między Java a C++ się zaciera...
Tutaj link do Quake 2 w Javie (za free wersja demo)
http://www.bytonic.de/html/jake2.html

0

Czyli tak na prawdę to wiele jest stereotypów typu, że programy w C++ z reguły są szybsze niż pisane w Javie albo C# ?

To nie jest kwestia języka, tylko kompilatora (i w przypadku C# i Javy - maszyny wirtualnej). Jednym z założeń C++ jest, że ma być szybki: i na to nakłada się największy nacisk w pisaniu kompilatorów. Ale Jak tu niedawno ze zdziwieniem ktoś zauważył, nowe wersje Delphi są zadziwiająco szybkie...

za to FreePascala (Lazarusa) uważam za raczej powolnego, przy tym samym kodzie co w Delphi - sromotnie przegrywa.

0

Przepisałem kod na C++ (skompilowany przy użyciu MS Visual C++ 2010 Express) jako aplikacja konsolowa.
Wynik dla Java przy 1 mb pliku - 1 sekunda, dla C++ 9 sekund (ten sam plik)
Kod w C++

 
#include "stdafx.h"


using namespace std;




int _tmain(int argc, _TCHAR* argv[])
{
	   int liczba_zamian = 0;

	int czas1, czas2;
    czas1=clock();  // za czas1 zostanie wstawiony czas w milisekundach od momentu wlaczenia programu
    string wczytany_tekst2 = "";
    string line;
  ifstream myfile ("test1.txt", ifstream::in);
  if (myfile.is_open())
  {
	  cout << "Otworzono plik! ";
	  cout << endl;
    while ( myfile.good() )
    {
      getline (myfile,line);
	  //wczytany_tekst2.append(wczytany_tekst2);
      wczytany_tekst2.append(line);
	  wczytany_tekst2.append("\r\n");
    }
    myfile.close();
	cout << "Wczytano plik !" << endl;
  }
 
size_t j;
string find = "[";
string replace = "{";
cout << "Dokonywanie zamiany... ";
for ( ; (j = wczytany_tekst2.find( find )) != string::npos ; ) {
wczytany_tekst2.replace( j, find.length(), replace );
}
find = "]";
replace = "}";
for ( ; (j = wczytany_tekst2.find( find )) != string::npos ; ) {
wczytany_tekst2.replace( j, find.length(), replace );
}
cout << "OK!" << endl;
cout << "Zapis do pliku... " ;
ofstream myfile2 ("test1.txt");
  if (myfile2.is_open())
  {
    myfile2 << wczytany_tekst2;
    myfile2.close();
  }
cout << "OK!" << endl;

    czas2=clock();
    czas2=czas2-czas1;
   cout << "Czas zamiany wynosi : " << czas2 << " ms (" << czas2/1000 << " sekund)";

   system ("pause");
  

	return 0;
}

Korzystając z biblioteki wxWidgets + kompilator MingGW 3.4.5 (wxDevCpp) to czas zamiany wynosił 19 sekund... (metoda Replace klasy wxString).

Pytanie jest o samo wyszukiwanie i zamianę stringów... bo ten algorytm jest powolny...

0

Przepisałem kod na C++
ten kod to taki trochę WTF-owy był, porównaj czas z tym:

#include <iostream> 
#include <fstream>
#include <ctime>
#include <string>
using namespace std;

int main(int argc, char argv[])
{
	clock_t timeStart, timeTotal;
	timeStart=clock();
	ifstream inputFile("test1.txt", ios::in);
	ofstream outputFile("test2.txt", ios::out);
	if (!inputFile || !outputFile)
	{
		cout << "Kupa."<<endl;
		exit(1);
	}
	string line;
	while (getline(inputFile,line))
	{
		int len = line.length();
		for (int i=0; i<len; i++)
		{
			if (line[i]=='[')
				line[i]='{';
			else if (line[i]==']')
				line[i]='}';
		}
		outputFile << line << '\n';
	}
	inputFile.close();
	outputFile.close();
	timeTotal=clock()-timeStart;
	cout << "Czas zamiany wynosi : " << timeTotal << " ms (" << timeTotal/1000 << " sekund)";
	system ("pause");
	return 0;
}

EDIT: a jeżeli mamy wyszukiwać całe stringi to i tak nie trzeba "appendować" całego pliku do jednego długiego stringa, można czytać i zapisywać linia po linii. to się tyczy każdego języka.

0

No działa zdecydowanie szybciej. Tylko czy da się tak zrobić, żeby zmieniać nie tylko pojedynczy znak, ale np. kilka znaków zastąpić innymi? A może linijka po linijce wyszukiwać i wtedy korzystać z funkcji dostępnej w danym frameworku, niż w całym ogromnym stringu?

0

Proszę użyć funkcji StrReplaceCS z biblioteki JEDI pobrany z http://www.koders.com/delphi/fidCFF482EC7371D43AAF1241D90C486EDE5F0F568A.aspx

procedure StrReplaceCS(var S: AnsiString; const Search, Replace: AnsiString; Flags: TReplaceFlags);
var
  ResultStr: string;     { result string }
  SourcePtr: PChar;      { pointer into S of character under examination }
  SourceMatchPtr: PChar; { pointers into S and Search when first character has }
  SearchMatchPtr: PChar; { been matched and we're probing for a complete match }
  ResultPtr: PChar;      { pointer into Result of character being written }
  SearchLength,          { length of search string }
  ReplaceLength,         { length of replace string }
  ResultLength: Integer; { length of result string (maximum, worst-case scenario) }
  C: Char;               { first character of search string }
begin
  //if (S = '') or (Search = '') then Exit;
  { avoid having to call Length() within the loop }
  SearchLength := Length(Search);
  ReplaceLength := Length(Replace);
  { initialize result string to maximum (worst case scenario) length }
  if Length(Search) >= ReplaceLength then
    ResultLength := Length(S)
  else
    ResultLength := ((Length(S) div Length(Search)) + 1) * Length(Replace);
  SetLength(ResultStr, ResultLength);
  { get pointers to begin of source and result }
  ResultPtr := PChar(ResultStr);
  SourcePtr := PChar(S);
  C := Search[1];
  { while we haven't reached the end of the string }
  while True do
  begin
    { copy characters until we find the first character of the search string }
    while (SourcePtr^ <> C) and (SourcePtr^ <> #0) do
    begin
      ResultPtr^ := SourcePtr^;
      Inc(ResultPtr);
      Inc(SourcePtr);
    end;
    { did we find that first character or did we hit the end of the string? }
    if SourcePtr^ = #0 then
      Break
    else
    begin
      { continue comparing, +1 because first character was matched already }
      SourceMatchPtr := SourcePtr + 1;
      SearchMatchPtr := PChar(Search) + 1;
      while (SourceMatchPtr^ = SearchMatchPtr^) and (SearchMatchPtr^ <> #0) do
      begin
        Inc(SourceMatchPtr);
        Inc(SearchMatchPtr);
      end;
      { did we find a complete match? }
      if SearchMatchPtr^ = #0 then
      begin
        { append replace to result and move past the search string in source }
        Move((@Replace[1])^, ResultPtr^, ReplaceLength);
        Inc(SourcePtr, SearchLength);
        Inc(ResultPtr, ReplaceLength);
        { replace all instances or just one? }
        if not (rfReplaceAll in Flags) then
        begin
          { just one, copy until end of source and break out of loop }
          while SourcePtr^ <> #0 do
          begin
            ResultPtr^ := SourcePtr^;
            Inc(ResultPtr);
            Inc(SourcePtr);
          end;
          Break;
        end;
      end
      else
      begin
        { copy current character and start over with the next }
        ResultPtr^ := SourcePtr^;
        Inc(ResultPtr);
        Inc(SourcePtr);
      end;
    end;
  end;
  { append null terminator, copy into S and reset the string length }
  ResultPtr^ := #0;
  S := ResultStr;
  SetLength(S, StrLen(PChar(S)));
end;
 

Proszę podać czas operacji zamiany po zmianie funkcji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1