Autor Beitrag
xsus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 51

Win 2000, Win XP, Win 7; Ubuntu
Delphi 7, Delphi XE2, C
BeitragVerfasst: Di 06.08.13 23:19 
Hey,

ich bin an einem kleinen Testprogramm am schreiben (soll später in ein größeres Projekt integriert werden). Zum jetzigen Zeitpunkt soll das Programm bei Eingabe ins Edit1-Feld (+Buttonclick) eine Reihe von ListItems durchgehen und vergleichen. Anschließend soll die Prozedur mit dem jeweiligen Namen (also der eingegebene) ausgeführt werden.
Testweise sieht das wiefolgt aus: Die Begriffe : Photosynthese, DNA und Adhäsion sollen eingegeben werden können und die jeweilige Prozedur markiert einen RadioButton...
Leider kommt es regelmäßig zu Stackoverflows und ich habe keine Ahnung wieso...bei Photosynthese und DNA als Begriff scheint es zu klappen...liegt es evtl. an Ä;Ü;Ö? Wie kann ich auch diese Buchstaben vergleichen lassen?

Wieso ändert sich der Fenstertitel und wie kann ich das verhindern?

//Die Eingabe von den 3 Begriffen (Photosynthese,..) habe ich manuell über die Eigenschaften in die ListBox gesetz, .., tauchen also nicht im Quellcode auf

Quellcode:
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:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    RadioButton1: TRadioButton;
    RadioButton2: TRadioButton;
    RadioButton3: TRadioButton;
    Button1: TButton;
    ListBox1: TListBox;
    procedure Photosynthese;
    procedure DNA;
    procedure Adhaesion;
    procedure ItemsWeiter;
    procedure start;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  TEXT:String;
  Zahl:integer;

implementation

{$R *.dfm}

procedure TForm1.Photosynthese;
begin
RadioButton1.Checked:=true;
end;

procedure TForm1.DNA;
begin
RadioButton2.Checked:=true;
end;

procedure TForm1.Adhaesion;
begin
RadioButton3.Checked:=true;
end;

function vergleicheStringsN(s1, s2:string; n:Word): Boolean;
  function delLZ(s: string): string;
  var ss: string;
      i,j: Word;
  begin
   j:=0; ss:='';
   for i:=1 to Length(s) do
   begin
    if (s[i] <> ' 'and (s[i] <> '-'then
    begin
     Inc(j);
     ss:= ss + s[i]
    end;
    if j=n then Break
   end;
   Result := UpperCase(ss)
  end;
 begin
  if delLZ(s1)=delLZ(s2) then Result:=True else Result:=False ;
 end;

procedure TForm1.ItemsWeiter;
begin
    if zahl=ListBox1.Items.Count -1 then begin end else
    begin
    Text := ListBox1.Items.Strings[zahl];
    zahl:=zahl+1;
    end;
 end;

procedure TForm1.start;
begin
ItemsWeiter;
if vergleicheStringsN(Edit1.Text, Text, 8)=True then
   case zahl of
   1: Photosynthese;
   2: DNA;
   3: Adhaesion;
   end
else
start;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
start;
end;
end.


Z.Zt. steht mir leider nur Delphi 7 zur Verfügung..

Grüße und Dank von
xsus
Mathematiker
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1448

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: Di 06.08.13 23:33 
Hallo,
user profile iconxsus hat folgendes geschrieben Zum zitierten Posting springen:
Wieso ändert sich der Fenstertitel und wie kann ich das verhindern?
...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm1.ItemsWeiter;
begin
    if zahl=ListBox1.Items.Count -1 then begin end else
    begin
    Text := ListBox1.Items.Strings[zahl];   // <-- hier ist das Problem
    zahl:=zahl+1;
    end;
 end;

"Text" als globale Variable ist sehr ungünstig, da in dieser Methode die Variable Text = Form1.Text ist, d.h. also der Fenstertitel. Globale Variablen sind an sich nicht so prickelnd.
Hier würde ich einfach Umbenennen, z.B. "Suchtext" oder so, empfehlen.
Eine Idee für die anderen Problemen braucht noch etwas Zeit.

Beste Grüße
Mathematiker

Nachtrag: In
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TForm1.start;
begin
ItemsWeiter;
if vergleicheStringsN(Edit1.Text, Text, 8)=True then
   case zahl of
   1: Photosynthese;
   2: DNA;
   3: Adhaesion;
   end
else
start;
end;

rufst Du die Methode start rekursiv auf. Wenn ich das richtig sehe, wird diese damit nur dann beendet, wenn der letzte String der Listbox Deinem "Text" (Ändern!) entspricht.
Das führt in der Regel zum Stacküberlauf.

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein

Für diesen Beitrag haben gedankt: xsus
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Mi 07.08.13 07:57 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
function vergleicheStringsN(s1, s2:string; n:Word): Boolean;
  function delLZ(s: string): string;
  var ss: string;
      i,j: Word;
  begin
   j:=0; ss:='';
   for i:=1 to Length(s) do
   begin
    if (s[i] <> ' 'and (s[i] <> '-'then
    begin
     Inc(j);
     ss:= ss + s[i]
    end;
    if j=n then Break
   end;
//   Result := UpperCase(ss) Lässt die Umlaute unverändert. Deswegen:
   Result := AnsiUpperCase(ss)
  end;
 begin
  if delLZ(s1)=delLZ(s2) then Result:=True else Result:=False ;
 end;


UpperCase berücksichtigt die (deutschen) Sondezeichen nicht. Daher musst du AnsiUpperCase verwenden.

Für diesen Beitrag haben gedankt: xsus
xsus Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 51

Win 2000, Win XP, Win 7; Ubuntu
Delphi 7, Delphi XE2, C
BeitragVerfasst: Mi 07.08.13 13:01 
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,
"Text" als globale Variable ist sehr ungünstig, da in dieser Methode die Variable Text = Form1.Text ist, d.h. also der Fenstertitel. Globale Variablen sind an sich nicht so prickelnd.
Hier würde ich einfach Umbenennen, z.B. "Suchtext" oder so, empfehlen.
Eine Idee für die anderen Problemen braucht noch etwas Zeit.


Ja, das hat Super geklappt! Danke :)

Zu dem Anderem - sowohl Uppercase als auch AnsiUpperCase machen keinen unterschied. :/

Wenn ich das Recht sehe, muss die ItemsWeiter und die Start-Procedure verändert werden. Ich habe jetzt div. Versucht, aber ohne Erfolg. Im Prinzip soll ja nur bei jeder Suchanfrage die ItemsListe durchgegangen werden und jedes Item jeweils verglichen werden. Anschließend die Nummer übergeben um die entsprechende Procedure auszuführen. Keiner eine Idee? :)

Beste Grüße!
Mathematiker
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1448

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: Mi 07.08.13 13:36 
Hallo,
so ähnlich dürfte es funktionieren:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure TForm1.start;
var i:integer;
    s:string;
begin
    i:=0;
    repeat
      s:=listbox1.items[i];
      if vergleicheStringsN(Edit1.Text, s, 8)=True then
        case i+1 of
         1: Photosynthese;
         ...
        end
      inc(i);
    until i>listbox1.items.count-1;
end;

Du benötigst keine globale Variable und keinen rekursiven Aufruf mehr.

Beste Grüße
Mathematiker

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein

Für diesen Beitrag haben gedankt: xsus
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Mi 07.08.13 13:38 
Gelöscht,

ich habe in der Eile nicht erkannt, dass Mathematiker schon zuvor gepostet hat, welches auch eine bessere Version ist.

Gruß Horst
P.S.
Wie wird man den Dank wieder los?


Zuletzt bearbeitet von Horst_H am Do 08.08.13 07:19, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: xsus
FinnO
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: Mi 07.08.13 17:21 
Bitte keine Vergleiche auf True durchführen.

Besser:

ausblenden Delphi-Quelltext
1:
2:
if vergleicheStringsN(Edit1.Text, Text, 8then 
...
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Do 08.08.13 12:18 
Auch wenn ich mich unbeliebt machen sollte: ein paar Dinge stören mich an der Lösung. Zum Einen knallt es aufgrund der Fußschleife, sobald die ListBox keine Einträge enthält, da ungeprüft auf den String an Index 0 zugegriffen wird. Zum Anderen ist das Ganze durch die Vermischung von Logik und Darstellung unflexibel, man will doch eigentlich keine VCL-Controls vergleichen, sondern deren Inhalt, also Strings. Schöner fände ich persönlich es daher, wenn man eine allgemeinverwendbare Lösung anstreben würde. So etwas könnte z.B. so aussehen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
type
  TMatchFunc = function(String1, String2: string): Boolean;

function SpecialIndexOf(SearchString: string; List: TStrings;
  MatchFunc: TMatchFunc): integer;
var
  idx: integer;
begin
  Assert(Assigned(List), 'Vergleichsliste nicht übergeben');
  Assert(Assigned(MatchFunc), 'Vergleichsroutine nicht übergeben');
  Result := -1;
  for idx := 0 to List.Count - 1 do
    if MatchFunc(SearchString, List[idx]) then
      begin
        Result := idx;
        break;
      end;
end;

Dadurch, dass man die Vergleichsroutine selbst schreiben muss, ist man in eben dieser völlig frei und kann mit den übergebenen Strings anstellen, was man will/muss. 2 Beispiele dazu:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
function MatchFunc1(String1, String2: string): Boolean;
begin
  Result := AnsiLowerCase(String1) = AnsiLowerCase(String2);
end;

procedure TFormTest.Button1Click(Sender: TObject);
var
  List: TStringlist;
begin
  List := TStringList.Create;
  try
    List.Add('Dies');
    List.Add('ist');
    List.Add('ein');
    List.Add('Test');
    ShowMessage(IntToStr(SpecialIndexOf('EIN', List, MatchFunc1)));
  finally
    List.Free;
  end;
end;

Das war jetzt noch keine große Kunst, daher hier ein wenig komplexer:
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:
function MatchFunc2(String1, String2: string): Boolean;

  function FilterNumbers(const s: string): string;
  var
    Src, Dest, Current: PChar;
  begin
    SetLength(Result, Length(s));
    Src := PChar(s);
    Dest := PChar(Result);
    Current := Dest;
    while Src^ <> #0 do
      begin
        if Src^ in ['0'..'9'then
          begin
            Current^ := Src^;
            Current := CharNext(Current);
          end;
        Src := CharNext(Src);
      end;
    SetString(Result, Dest, Current - Dest);
  end;

begin
  Result := FilterNumbers(String1) = FilterNumbers(String2);
end;

procedure TFormTest.Button2Click(Sender: TObject);
var
  List: TStringlist;
begin
  List := TStringList.Create;
  try
    List.Add('Dies');
    List.Add('ist123');
    List.Add('ein');
    List.Add('Test');
    ShowMessage(IntToStr(SpecialIndexOf('Didel123dum', List, MatchFunc2)));
  finally
    List.Free;
  end;
end;

Man ist bei Verwendung von SpecialIndexOf an keine VCL-Controls mehr gebunden und kann die Vergleichsroutine (den Callback) völlig frei gestalten. Evtl. ist noch der eine oder andere Fehler enthalten, mir ging es aber vorrangig um das Prinzip.

Für diesen Beitrag haben gedankt: FinnO, Marc.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Do 08.08.13 14:12 
Hallo,

xsus ist ja noch Schüler, da kann man noch etwas bewirken, entschuldige...

wie bekommt man das hin
ausblenden Delphi-Quelltext
1:
  Assert(Assigned(MatchFunc), 'Vergleichsroutine nicht übergeben');					

ohne das der Compiler nicht hier schon vorher meckert?
ausblenden Delphi-Quelltext
1:
showMessage(IntToStr(SpecialIndexOf('EIN', List, MatchFunc1)));					

Oder stellst Du Dir die Verwendung eines array of TMatchfunc vor, indem dann NIL steht
ausblenden Delphi-Quelltext
1:
showMessage(IntToStr(SpecialIndexOf('EIN', List, MatchFuncArr[1])));					


Ein großer Vorteil bei der Verwendung einer seperaten Liste besteht in der Möglichkeit, die Daten schon dort in das gewünschte Format zu bringen, ohne sie ständig umwandeln zu müssen.
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:
  function delLZ(s: string,MaxLen : word): string;
  var 
      i,j: Word;
  begin
   j:=length(s);;
   IF maxLen > j then
     maxLen := j;
     
   j := 1;
   setlength(result,maxLen);
   for i:=1 to Length(s) do
   begin
    if (s[i] <> ' 'and (s[i] <> '-'then
    begin
     result[j] := s[i];
     Inc(j)
    end;
    if j>MaxLen then 
      Break
   end;
   setlength(result,j-1);
   Result := AnsiUpperCase(result)
  end;
...

procedure TFormTest.Button1Click(Sender: TObject);
var
  List: TStringlist;
  i : integer; 
begin
  Assert(Assigned(ListBox1), 'Keine ListBox1 vorhanden');
  i := ListBox1.Items.Count;
  IF i = 0 then
    Assert(false, 'Nichts vorhanden');    
  List := TStringList.Create;
  try
    List.capacity := i;
    For i := i-1 downto 0 do
      List[i] := delLZ(ListBox1.Items.Strings[i], 8);
    ShowMessage(IntToStr(SpecialIndexOf(delLZ('EIN'), List, MatchFunc1)));
  finally
    List.Free;
  end;
end;


Gruß Horst
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Do 08.08.13 17:05 
user profile iconHorst_H hat folgendes geschrieben Zum zitierten Posting springen:
wie bekommt man das hin
ausblenden Delphi-Quelltext
1:
  Assert(Assigned(MatchFunc), 'Vergleichsroutine nicht übergeben');					

ohne das der Compiler nicht hier schon vorher meckert?
ausblenden Delphi-Quelltext
1:
showMessage(IntToStr(SpecialIndexOf('EIN', List, MatchFunc1)));					

Indem man statt MatchFunc1 einfach nil übergibt? Und damit man das eben nicht tut, wird die Assertion aktiv.