Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Wörter zählen, optmimieren? (https://www.delphipraxis.net/7764-woerter-zaehlen-optmimieren.html)

Baumel 20. Aug 2003 23:10


Wörter zählen, optmimieren?
 
Hallo,
ich möchte die Wörter in einem Rtf-Feld zählen. Dazu habe ich folgenden Code verwendet (s.auch http://www.delphipraxis.net/internal...6rter+z%E4hlen).

Es funktioniert ja eigentlich auch, aber nur unheimlich langsam. Auch die schnellere Variante, die nur auf Leerzeichen prüft, ist bei Texten größer als 100KByte zu langsam (ab 300KByte Text wirds richtig lahm). In Word oder Works gibt es auch so eine Funktion, nur dort ist diese blitzschnell.
Hat jemand Optimierungsvorschläge oder andere meth. Ansätze?
Delphi-Quellcode:
function TEditor.CountWordsSlow(minwordlength:Integer):Integer;
var s: string;
    c: char;
    i, l, le:Integer;
begin
  i:=0;
  le:=Length(Text);
  s:='';
  if le > 0 then
  for l:=1 to le do
  begin
    c:=Text[l];
    if (Upcase(c) in ['A'..'Z','Ä','Ö','Ü','ü','ö','ä','ß']) then s:=s+c
    else
    begin
      if (Length(s) >= minwordlength) Then Inc(i);
      s:='';
    end;
  end;
  CountWordsSlow:=i;
end; {TEditor.CountWords}


function TEditor.CountWordsFast(minwordlength:Integer):Integer;
var s: string;
    c: char;
    pnow, plast,i,l,le:Integer;
begin
  //erste Variante
  (*
  i:=0;
  le:=Length(Text);
  pnow:=1;
  plast:=1;
  if le > 0 then
  for l:=1 to le do
  begin
    if Text[l]=' ' then
    begin
      plast:=pnow;
      pnow:=l;
      if (pnow-plast) > minwordlength then inc(i);
    end;
  end; {for}
  *)
  // zweite Variante
  s:=Text;
  i:=0;
  pnow:=1;
  if Length(s) > 0 then
  while pnow > 0 do
  begin
    pnow:=Pos(' ',s);
    if pnow >= minwordlength then inc(i);
    Delete(s, 1,pnow);
  end;
  //Rest
  CountWordsFast:=i;
end; {TEditor.CountWordsFast}
[edit=Daniel B]Delphi-Tags korrigiert. Mfg, Daniel B[/edit]

Aya 20. Aug 2003 23:18

Re: Wörter zählen, optmimieren?
 
Hi,

ich hab gradmal was versucht...
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  cnt, i: Integer;
begin
  cnt:=0;
  for i:=1 to Length(RichEdit1.Text) do
    if RichEdit1.Text[i] = ' ' then
      Inc(cnt);
  ShowMessage(IntToStr(cnt));
end;
Das ist wahnsinnig langsam... aber diese version:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  S: String;
  cnt, i: Integer;
begin
  cnt:=0;
  S:=RichEdit1.Text;
  for i:=1 to Length(S) do
    if S[i] = ' ' then
      Inc(cnt);
  ShowMessage(IntToStr(cnt));
end;
ist rasend schnell... bei nem 1mb Text dauert es keine 10tel Sekunde (Also klick auf Button und sofort isses ausgezählt!)

Hoffe das hilft dir ein wenig :)

Au'revoir,
Aya~

Baumel 20. Aug 2003 23:42

Re: Wörter zählen, optmimieren?
 
Zitat:

S:=RichEdit1.Text;

Hoffe das hilft dir ein wenig :)
Hmmm, jau. Jetzt gehts ab. Die minimalen Änderungen bei der function CountWordsSlow bringen es. Schwupps das Ergebnis ist sofort da - ohne den Änderungen konnte ich mitunter ca. 15 Minuten Däumchendrehen.


Danke. :P :lol:

JoelH 21. Aug 2003 05:15

hmm,
 
das ist aber arg ungenau ? Wörter könne doch auch durch Kommas etc. getrennt sein oder ?
Ich würd es umgekehrt machen in der abfrage
anstatt
Delphi-Quellcode:
 if s[i] = ' ' then ..
Delphi-Quellcode:
if not(s[i] in ['a'..'z','A'..'Z']) then ..

Chewie 21. Aug 2003 16:42

Re: Wörter zählen, optmimieren?
 
Das ist aber auch blöd. Was, wenn man ein Dollarzeichen schreibt :shock:

Als Trennzeichen dienen i.d.R. Zeilenumbrüche, Leerzeichen, Kommas, Strichpunkte und Tabs
Somit würde das dann etwa so aussehen:

Delphi-Quellcode:
if s[i] in [#9,#10,#13,#32,',','.',';'] then //...

Aufpassen muss man aber bei Trennstrichen vor Zeilenumbrüchen, denn das sind dann meist Silbentrennungszeichen. Befindet sich direkt vor einem Zeilenumbruch ein Minus-Strich(-), trennt der Zeilenumbruch das Wwort nicht.
Die Bedingung also folgendermaßen erweitern:
Delphi-Quellcode:
if s[i] in [#9,#10,#13,#32,',','.',';']) then
  if (s[i] = #13) and (s[i-1] <> '-') then //jetzt ein Wort

JoelH 21. Aug 2003 16:47

hmm,
 
ist allgemein schwierig weil es ist wie mit der deutschen Sprache, es gibt x Ausnahmen und Spezialfälle.
Also ich hab ein wenig Syntaxhighlighting versucht zu machen, gibt auch ein Posting dazu irgendwo hier, wie auch immer. Das parsen ist gar nicht so einfach. Schade dass Delphi keine reg. Expressions von Haus aus unterstützt, das ist einfach eine feine Sache (php,ruby,perl loben muss).

Baumel 21. Aug 2003 16:53

Re: Wörter zählen, optmimieren?
 
Hi,

Zitat:

das ist aber arg ungenau ? Wörter könne doch auch durch Kommas etc. getrennt sein oder ? ...
ich nutze jetzt auch function CountWordsSlow mit der Modifikation, das nicht mehr direkt auf die RTF.Text zugegriffen wird. Der Inhalt wird nun in einen String s kopiert und damit wird dann gearbeitet. Seitdem habe ich keine Performance-Probleme mehr.

Ich dachte anfangs die Performanceeinbußen kamen durch die Mengenoperationen In [...].
Deshalb hatte ich einen anderen, schnelleren (und wie du zurecht bemerkst) äußerst ungenauen Ansatz gewählt (CountWordsFast). Wirklich schneller lief der auch nicht.


Gruß
Dirk

Christian Seehase 21. Aug 2003 16:57

Re: Wörter zählen, optmimieren?
 
Moin Dirk,

bei jeder Art Stringliste, eben auch RichEdit.Lines, wird die Eigenschaft Text bei jedem Lesezugriff auf diese Eigenschaft aus den gesamten Strings zusammengesetzt, und bei jedem Schreibzugriff werden die Zeilen anschliessend neu aufgebaut.
Das ist das, was so auf die Performance drückt.

bjacke 19. Okt 2004 14:55

Re: Wörter zählen, optmimieren?
 
[quote="Aya"]Hi,

ich hab gradmal was versucht...
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  cnt, i: Integer;
begin
  cnt:=0;
  for i:=1 to Length(RichEdit1.Text) do
    if RichEdit1.Text[i] = ' ' then
      Inc(cnt);
  ShowMessage(IntToStr(cnt));
end;
Das ist wahnsinnig langsam... aber diese version:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  S: String;
  cnt, i: Integer;
begin
  cnt:=0;
  S:=RichEdit1.Text;
  for i:=1 to Length(S) do
    if S[i] = ' ' then
      Inc(cnt);
  ShowMessage(IntToStr(cnt));
end;
Hier habe ich aber das Problem, dass auch Leerzeichen mitgezählt werden. Ich habe den Quelltext vollgender Maßen ergänzt:
Delphi-Quellcode:
Var i,count:integer; text:string;
Delphi-Quellcode:
count:=0;
Text:=Rich.Text ;
for i:=1 to length(Text) do
if Text[i]=' ' then if (Text[i+1]<>' ') then inc(count);

LarsMiddendorf 19. Okt 2004 16:15

Re: Wörter zählen, optmimieren?
 
Da mußt du aber wegen dem i+1 und der Länge des Strings aufpassen.

notErnie 19. Okt 2004 23:42

Re: Wörter zählen, optmimieren?
 
Bei den Trennzeichen für's "Wörter zählen" sollte man vielleicht auch noch Frage- und Ausrufungszeichen (?!) berücksichtigen :)

Nicht jeder will nur die Wörter im Sourcecode zählen :mrgreen:

Bert

Nothine 20. Okt 2004 00:31

Re: Wörter zählen, optmimieren?
 
der ansatz die trennzeichen zu zählen ist ja ganz interessant, aber es gibt alle möglichen arten von trennungen, manchmal^würden^menschen sowas sogar zusammenschreiben, was macht man da? sich mal meinen vorschlag anhören :mrgreen:

wörter bilden sich im regelfall aus buchstaben, dafür sind sie bekannt, also warum nicht sobald ein wort anfängt den counter erhöhen und bis zum ende des wortes weitergehen? konkret sähe das folgendermaßen aus...
Delphi-Quellcode:
function WordCount(const S: string): Integer;
const ValidChars = ['a'..'z','A'..'Z','ä','ö','ü','Ä','Ö','Ü','ß'];
var P: PChar;
begin
  Result := 0;
  if S = '' then Exit;
  P := Pointer(S);
  repeat
    if P^ in ValidChars then begin
      while (P^ in ValidChars) and (P^ <> #0) do
        Inc(P);
      Inc(Result);
    end else Inc(P);
  until P^ = #0;
end;

notErnie 20. Okt 2004 01:39

Re: Wörter zählen, optmimieren?
 
@Nothine:

Den Ansatz hatten wir (fast) schon mal weiter oben - ohne die Pointer.

Aus Deiner Idee kann noch was werden, wenn Du Deine "ValidChars" noch um Zahlen oder z.B. italienische, spanische oder türkische Buchstaben erweiterst...

Aber so im Großen und Ganzen bevorzuge ich doch eher das Parsen nach Trennzeichen :pale:

Tschulligung: "Wörter zählen" ist (und bleibt) leider ein Scheiß-Thema, das möglicherweise zu lösen wäre, wenn ...

...wenn es nur eine Sprache gäbe...

Komplett naive (realitätsfremde) Grüße daher/dazu von
Bert

negaH 20. Okt 2004 08:52

Re: Wörter zählen, optmimieren?
 
Zitat:

bei jeder Art Stringliste, eben auch RichEdit.Lines, wird die Eigenschaft Text bei jedem Lesezugriff auf diese Eigenschaft aus den gesamten Strings zusammengesetzt, und bei jedem Schreibzugriff werden die Zeilen anschliessend neu aufgebaut.
Das ist das, was so auf die Performance drückt.
Das stimmt für Delphis TStringList Objecte, aber eben nicht für RichtEdits. RichEdits verwalten intern den kompletten Textin einem linearen Speicher. Bei jedem Zugriff auf die Property .Text wird intern nun vom Windows API RichEdit Control der Text angefordert. Nun, das Windows API läuft bekannt bei Fensterhandles immer über Messages. D.h. .GetText muß mie SendMessage() arbeiten, intern wird dann der Text-Speicher in den vorher allozierten String kopiert. Pro Zugriff auf die Property .Text entstehen also 2 SendMessages (1 um die Größe des Textes zu holen, 1 um den Text zu holen) + eine Speicherallozierung eines LongStrings mit Setlength() und eine Speicherkopierung. Sollte der Text also 1Mb betragen, wird jedesmal beim Aufruf von .Text[I] ein neuer Speicherbereich mit 1Mb Daten kopiert.
Das das langsam sein muß ist ja wohl klar.

Gruß Hagen

PS: Variablen sind die Freunde des Programmierers ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:54 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz