Autor Beitrag
galagher
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2562
Erhaltene Danke: 46

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mi 07.01.09 20:58 
Hallo!

Das geht doch auch anders, ich glaube, schneller:
ausblenden Delphi-Quelltext
1:
 s := s+Text[i];					

Aber ich komm' nicht drauf, wie. Ich wüsste auch nicht, wonach ich da suchen sollte. Ich glaube nur, dass es da auch noch eine andere Art gibt, an s anzuhängen. Hat jemand eine Idee?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 07.01.09 21:16 
Grundsätzlich nicht, in speziellen Fällen gibts da auch Tricks. Nämlich dann, wenn du in einer Schleife jeweils einen Buchstaben anhängst, der String also immer weiter wächst.
In dem Fall kannst du einfach vorher die Länge hochsetzen und danach auf die tatsächliche Länge kürzen.

Und für das Setzen der einzelnen Buchstaben gibts auch noch Tricks um die Performance zu erhöhen. Ich bin so auf ca. 150.000.000 verarbeitete Buchstaben pro Sekunde gekommen bei einer Entschlüsselung. ;-)

// EDIT:
Ach ja: Und wenn Text die Eigenschaft eines Memos ist: Lies das vorher in einen String statt immer wieder auf den Memoinhalt zuzugreifen.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2562
Erhaltene Danke: 46

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mi 07.01.09 22:01 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Nämlich dann, wenn du in einer Schleife jeweils einen Buchstaben anhängst, der String also immer weiter wächst.
In dem Fall kannst du einfach vorher die Länge hochsetzen und danach auf die tatsächliche Länge kürzen.

Kannst du mir ein einfaches Beispiel geben?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 07.01.09 22:34 
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2562
Erhaltene Danke: 46

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mi 07.01.09 22:46 
user profile iconDeddyH hat folgendes geschrieben Zum zitierten Posting springen:
[url=www.delphiforum.de/v...=541096#541096[/url]

Danke! Sowas in der Art!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 07.01.09 22:58 
Wenn du genauer zeigst was du da optimieren willst, dann lässt sich da auch mehr dazu sagen. ;-)
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2562
Erhaltene Danke: 46

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mi 07.01.09 23:28 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wenn du genauer zeigst was du da optimieren willst, dann lässt sich da auch mehr dazu sagen. ;-)

Ich dachte einfach, bei zB. nur 10 Schleifendurchläufen spielt das ja keine Rolle, aber bei einigen tausend könnte es ja etwas bringen, wenn man da optimiert. Vor allem, wenn diese Schleifendurchläufe immer wieder ausgeführt werden.

Ich weiss, dass es anders als s := s+Text[i] auch geht, es ist auch nicht aufwändig. Steht sogar im Delphi-Forum irgendwo, aber ich weiss absolut keinen Zusammenhang mehr oder auch nur ein Stichwort, wonach ich suchen könnte. Ich erinnere mich nur, dass es irgendwann irgendjemand in irgendeinem Thread irgendwo beiläufig erwähnt hat! :mrgreen:

Nicht, dass der Code so langsam wäre, aber einfach aus Interesse:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
 function WordatCaret: String;
 var
   i, n: Integer;
   s: String;
 begin
  s := '';

  with RichEdit1 do
  begin
   n := SelStart+1;

   {Wortanfang suchen}
   for i := SelStart downto 0 do
   begin
    if Text[i] = ' ' then break;
    Dec(n);
   end;

   {Wortende suchen}
   for i := n to Length(Text) do
   begin
    if (Text[i] = ' 'or (Text[i] = #13then break;
    s := s+Text[i];  // -> hier!
   end;
  end;

  Result := s;  {Das Wort}
end;

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 07.01.09 23:47 
Hier ist das Vorgehen das langsamste. Du kopierst die Zeichen einzeln. Stattdessen solltest du Anfang und Ende des Wortes suchen und danach das ganze Wort in einem Rutsch kopieren. Das kannst du auch mit CopyMemory machen, das wäre wohl am schnellsten. ;-)
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 08.01.09 09:17 
Du greifst für jedes Zeichen auf die Text-Eigenschaft des TRichedit-Controls zu. Die wiederum wird jedesmal aus den einzelnen Zeilen gebildet. Und das dürfte schonmal sehr langsam sein: Erstelle also zunächst eine Kopie des RichEdit-Textes in einer lokalen Variablen und arbeite mit dieser.

@jaenike: Wenn ich erst die Position des Wortes suche, und dann mit copyMemory arbeite, dann durchlaufe ich diese Stelle im String 2x (einmal zum Suchen und dann nochmals zum Kopieren). Das ist nach meiner Erfahrung langsamer, als das das stetige Kopieren eines Zeichens. Eventuell könnten CopyMemory-Spezialversionen von FastCode.org diesen Nachteil zunichte machen, es bliebe aber trotzdem beim zweimaligen Durchlaufen.

Selbst Konstrukte wie: s:=s+Text[i] sind nicht mehr böse Performancebremsen, da Delphi seit Version 2005(?) durch die Verwendung des optimierten Speichermanagers hier nicht jedesmal neuen Speicher zuweist. Es wäre trotzdem zu überlegen, ob man nicht 's' zunächst auf -sagen wir- 2000 Zeichen festsetzt und einmalig zum Schluss die konkrete Wortlänge festsetzt.

Abschließend wäre es hilfreich, die Funktion unabhängig vom TRichEdit zu machen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
Function WordAtCaret (Const sText : String; aCaretPos : Integer) : String;
Var
  iCaret, ResultPos : Integer;

Begin
  SetLength (Result, ciMaxWordLength);
  iCaret := aCaretPos + 1;
  While (iCaret>1And (sText[iCaret])=' ' Do Dec(iCaret); 
  ResultPos := 0;
  while (iCaret <= Length (sText)) And Not (sText[iCaret] in [' '#13]) Do Begin
    Inc (ResultPos);
    (* Wenn Wörter länger als ciMaxWordLength herauskommen können *)

 // If ResultPos>Length (Result) Then 
 //   SetLength (Result, Length (Result)+1000); 
    
    Result[ResultPos] := sText[iCaret];
    inc (iCaret);
  End;
  SetLength (Result, ResultPos);
End;
...
// Aufruf:
  TheWord := WordAtCaret (RichEdit.Text, RichEdit.SelStart);

Setze die Konstante ciMaxWordLength auf soetwas wie 1000 (oder z.B. 200, wenn keine Zeile länger als 200 Zeichen ist)

_________________
Na denn, dann. Bis dann, denn.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2562
Erhaltene Danke: 46

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 08.01.09 18:39 
user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Selbst Konstrukte wie: s:=s+Text[i] sind nicht mehr böse Performancebremsen, da Delphi seit Version 2005(?) durch die Verwendung des optimierten Speichermanagers hier nicht jedesmal neuen Speicher zuweist. Es wäre trotzdem zu überlegen, ob man nicht 's' zunächst auf -sagen wir- 2000 Zeichen festsetzt und einmalig zum Schluss die konkrete Wortlänge festsetzt.
Ich benutze Delphi 6.

Leider klappt dein Code nicht. Statt des Aufrufes
ausblenden Delphi-Quelltext
1:
TheWord := WordAtCaret (RichEdit.Text, RichEdit.SelStart);					

müsste man
ausblenden Delphi-Quelltext
1:
TheWord := WordAtCaret (RichEdit.Text, RichEdit.SelStart - Länge_des_Wortes);					

angeben, aber die Länge des Wortes ist ja zunächst noch unbekannt, da das Wort ja erst ermittelt werden soll!

Es soll eine Rechtschreibkorrektur als Teil eines Programms werden. Jedesmal, wenn der Benutzer die Leertaste oder Enter drückt, soll das letzte Wort korrigiert werden.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2562
Erhaltene Danke: 46

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 08.01.09 19:12 
Geht natürlich, aber was mir nicht gefällt, ist, dass ich eine globale Variable verwenden muss, die mir die Länge des Wortes angibt. Ich möchte nämlich das Wort im RichEdit selektieren und, falls nötig, korrigieren.
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
{Der Code ist im Wesentlichen von alzaimar (Delphi-Forum)}
function WordAtCaret(const sText: String; aCaretPos: Integer): String;
var
  iCaret, ResultPos, i: Integer;
begin
 SetLength (Result, 1000);//ciMaxWordLength);

 {Wortanfang suchen}
 for iCaret := aCaretPos downto 0 do
  if (sText[iCaret] in [' '#10]) then break;

 iCaret := iCaret+1;

 while (iCaret > 1and (sText[iCaret] = ' 'do Dec(iCaret);

 ResultPos := 0;

 {Wortende ermitteln}
 while (iCaret <= Length (sText)) and not (sText[iCaret] in [' '#13]) do
 begin
  Inc (ResultPos);
  {Wenn Wörter länger als 1000//ciMaxWordLength herauskommen können}
  {if ResultPos > Length (Result) then SetLength (Result, Length(Result)+1000);}
  Result[ResultPos] := sText[iCaret];
  Inc(iCaret);
 end;

 SetLength(Result, ResultPos);

 iWortLength := Length(Result); //naja, und hier die ungeliebte globale Variable.
end;

Für die Wortkorrektur gibt es eine Liste EingabeKorrL, die Items haben jeweils das Format wort|Wort - links = falsch, rechts = korrekt.
Der Aufruf:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
 {Das aktuelle Wort mit den "ShortHint's" in EingabeKorrL vergleichen, ...}
 for i := 0 to EingabeKorrL.Count-1 do
 begin
  if WordAtCaret(RichEdit1.Text, RichEdit1.SelStart) = GetShortHint(EingabeKorrL[i]) then
  begin                                       {... und wenn gefunden, ...}
   with RichEdit1 do
   begin
    Lines.BeginUpdate;
    SelStart := SelStart-iWortLength; //ich muss ja an den Anfang des Wortes gehen,
    SelLength := iWortLength;         //damit ich es selektieren kann!
    SelText := GetLongHint(EingabeKorrL[i]);  {... dieses korrigieren.}
    Lines.EndUpdate;
   end;
   break;
  end;
 end;

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 08.01.09 20:14 
Ich würde die Funktion so verändern, das sie den Wortanfang zurückliefert (iCaretPos).

_________________
Na denn, dann. Bis dann, denn.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2562
Erhaltene Danke: 46

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Fr 09.01.09 16:43 
user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
Ich würde die Funktion so verändern, das sie den Wortanfang zurückliefert (iCaretPos).

Einfacher ist, zuerst an eine Variable zuzuweisen: s := WordAtCaret(RichEdit1.Text, RichEdit1.SelStart); , dann kan man einfach mit Length(s) arbeiten.

Danke euch für die Hilfe!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2562
Erhaltene Danke: 46

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Fr 09.01.09 19:49 
Hier der komplette Code, getestet mit TMemo und TRichEdit. Wortkorrektur ist inkludiert!
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
{Anfang und Ende des Wortes, auf dem das Caret liegt, in einem TCustomMemo}
{ermitteln, mit WordCorrList vergleichen und, falls enthalten, selektieren}
{und korrigieren. Die Items müssen das Format  falsch|richtig  haben.}
{Der Code stammt im Original von alzaimar (Delphi-Forum).}
{http://www.delphi-forum.de/topic_Zeichen+an+Stringvariable+anhaengen_89220.html}
function WordCorrection(const CustomMemo: TCustomMemo;
 aCaretPos, iMaxWordLen: Integer; const WordCorrList: TStringList): String;
var
  iCaret, ResultPos, iPos: Integer;
  sText: String;
begin
 SetLength(Result, iMaxWordLen);

 sText := CustomMemo.Text;

 {iCaret initialisieren}
 iCaret := aCaretPos;

 {Wortanfang suchen}
 if aCaretPos > 1 then
  for iCaret := aCaretPos downto 0 do
   if (sText[iCaret] in [' '#0#10]) then break;

 Inc(iCaret);
 while (iCaret > 1and (sText[iCaret] = ' 'do Dec(iCaret);

 ResultPos := 0;

 {Wortende ermitteln}
 while (iCaret <= Length(sText)) and not (sText[iCaret] in [' '#13]) do
 begin
  Inc (ResultPos);

  {Wenn Wörter länger als iMaxWordLen herauskommen können}
  if ResultPos > Length(Result) then SetLength(Result, Length(Result)+iMaxWordLen);

  Result[ResultPos] := sText[iCaret];
  Inc(iCaret);
 end;

 SetLength(Result, ResultPos);
 if (Result = ''or (Pos(#10, Result) > 0or
    (Pos(#13, Result) > 0or (Pos(' ', Result) > 0then exit;


 {Das aktuelle Wort mit den "ShortHint's" in WordCorrList vergleichen, ...}
 for iCaret := 0 to WordCorrList.Count-1 do
 begin
  if Result = GetShortHint(WordCorrList[iCaret]) then
  begin                                            {... wenn gefunden, ...}
   with CustomMemo do
   begin
    iPos := SelStart;
    Lines.BeginUpdate;
    SelStart := SelStart-Length(Result);
    SelLength := Length(Result);
                             {... und keines dieser Zeichen enthalten, ...}
    if (Pos(' ', SelText) > 0or (Pos(#10, SelText) > 0or
       (Pos(#13, SelText) > 0then
    begin
     SelStart := iPos;
     Sellength := 0;
     Lines.EndUpdate;
     break;
    end;

    SelText := GetLongHint(WordCorrList[iCaret]);  {... dieses korrigieren.}
    Lines.EndUpdate;
   end;  {end von "with CustomMemo do"}
   break;
  end;  {end von "if Result = [...]"}
 end;  {end von "for iCaret := 0 do [...]"}
end;

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!