Entwickler-Ecke

Sonstiges (Delphi) - Fehlersuche - Emailfilter


Spansky - So 22.04.07 13:07
Titel: Fehlersuche - Emailfilter
Ich habe folgenden Algorithmus geschrieben. Er soll aus einem String alle Emailadressen herausfiltern und in eine Listbox schreiben. Allerdings funktioniert er nicht richtig. Es entsteht eine Zugriffsverletzung.


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:
procedure SucheEmailAdressen(str : string);
var i,j:integer;
Adresse : boolean; //Gibt an, ob es sich bei einem Wort um eine EmailAdresse handelt
var email : string;
begin
  i:=0;
  repeat
    begin
      if str[i]=' ' then //Leerzeichen sind das Signal für ein neues Wort
      begin
        adresse:=false;
        j:=i;//Notwendige Variable zur Einzelwortüberprüfung
        repeat //Schleife zum Untersuchen eines Wortes
          j:=j+1;
          email:=email+str[j];
          if str[j]='@' then adresse:=true; // wenn '@' im Wort => EmailAdresse
        until (str[j]=' 'or (j=length(str));// => Wortende bzw. Textende
        if adresse=true then Form2.ListBox1.AddItem(email,Form2.Listbox1); //Schreibe EmailAdresse in die Listbox
        email:='';//EmailAdresse zurücksetzen
        i:=j;//Einzelwortüberprüfung endet
        //i:=i+1;
      end;
      i:=i+1;
    end;
  until i=length(str);//Textende wurde erreicht
end;


Ich habs darauf hin mit ner anderen Lösung probiert:


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:
function StringIsEmail(str:string):boolean;//String = EmailAdresse???
var i:integer;
bed1,bed2:boolean;
begin
  result:=false;
  bed1:=false; bed2:=false;
  for i:=0 to length(str) do
  begin
    if str[i]='@' then bed1:=true;
    if str[i]='.' then bed2:=true;
    if bed1 and bed2 then result:=true
    else result:=false;
  end;
end;

function FindeWort(index:integer;str:string):string;//Filtert ein einzelnes Wort heraus. Der erste Buchstabe des Wortes liegt bei der Position index.
var i:integer;
begin
  i:=index;
  repeat
    result:=result+str[i];
    inc(i);
  until (i=length(str)) or (str[i]=' ');
end;

procedure FindEmailAdressen(str:string); //Letztendlicher Algorithmus mit Ausgabe
var i,p:integer;
begin
  i:=0;
  repeat
    p:=i;
    if StringIsEmail(FindeWort(p,str)) then Form2.ListBox1.AddItem(FindeWort(p,str),Form2.Listbox1);
    i:=i+length(FindeWort(p,str));
  until i=length(str);
end;


Auch hier entsteht wieder eine Schutzverletzung. Wo der Fehler liegt, ist mir ein Rätsel... vielleicht entdeckt ihr ihn ja. Ich hab Delphi 2005 PE benutzt.

Mfg,
Spansky


Dunkel - So 22.04.07 13:23

Was mir als Erstes aufgefallen ist: Strings fangen immer bei Index 1 an:


Delphi-Quelltext
 
6:
7:
8:
9:
10:
{ ... }
  i:=1;
  repeat
    begin
      if str[i]=' ' then
...


BenBE - So 22.04.07 13:29

Ferner solltest Du, wenn Du auf das Ende eines Strings prüfst i>=Length(Str) testen, da Du in deiner Schleife nicht explizit sicherstellen kannst, dass Du die Gleichheit je erreichen wirst. Erspart einem einiges an Debugging.


Spansky - So 22.04.07 13:41

Super. Die Schutzverletzung ist schonmal weg. Allerdings wird bei dem folgenden Aufruf der Funktion nur das hier ausgegeben:


Quelltext



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm2.Button1Click(Sender: TObject);
begin
  Listbox1.Items.Clear;
  //zw:=Clipboard.AsText;
  zw:='Hallo max.mustermann@test.de, wie geht es dir? Gruß frau.mustermann@test.de .';
  FindEmailAdressen(zw);
end;


BenBE - So 22.04.07 13:43

Kannst Du bitte kurz deinen aktuellen Source posten? Ich denk aber mal, dass Du nicht beachtet hast, dass beim Wegschneiden sich die Indizes im String verändern ;-)


Spansky - So 22.04.07 14:13

So hier is die Anwendung samt Source


BenBE - So 22.04.07 14:30

Kurz mal deinen Source überarbeitet ... ist aber ungetestet:


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:
unit Unit2;

interface

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

type
  TForm2 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;
  zw:string;
implementation

{$R *.dfm}
function StringIsEmail(str:string):boolean; //String = EmailAdresse???
var i:integer;
bed1,bed2:boolean;
begin
  result:=false;
  bed1:=false;
  bed2:=false;
  for i:=1 to length(str) do
  begin
    if str[i]='@' then bed1:=true; //Sollte prüfen auf genau ein @-Zeichen
    if str[i]='.' then bed2:=true; //In einer Email-Adresse brauch theoretisch auch gar kein Punkt vorkommen. user@host ist genauso gültig ;-) Teste das einfach mal mit einem Linux deines Vertrauens :P
    if bed1 and bed2 then result:=true
    else result:=false;
  end;
end;

function FindeWort(index:integer;str:string):string;
var i:integer;
begin
  i:=index;
  result := '';
  while (i<=length(str)) and not (str[i] in [' '','':']) do
  begin
    result:=result+str[i];
    inc(i);
  end;
end;

procedure FindEmailAdressen(str:string);
var i,p:integer;
    s:String;
begin
  i:=0;
  repeat
    p:=i;
    s:=FindeWort(p,str);
    if StringIsEmail(s) then Form2.ListBox1.AddItem(FindeWort(p,str),Form2.Listbox1);
    i:=i+length(s)+1;
  until i>=length(str); //Eigentlich ja nur >, da aber ein Einzelzeichen keine gültige Email-Adresse darstellen kann, darf auf >= vereinfacht werden.
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  Listbox1.Items.Clear;
  //zw:=Clipboard.AsText;
  zw:='Hallo max.mustermann@test.de, wie geht es dir? Gruß frau.mustermann@test.de .';
  FindEmailAdressen(zw);
end;

end.


Spansky - So 22.04.07 15:00

ok... funzt alles super. Die Unit wird jetzt noch nen bisschen weiterentwickelt und demnächst als Open-Source-Unit veröffentlicht. Danke für deine Hilfe, BenBE.