Autor Beitrag
ml-kuen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
BeitragVerfasst: So 29.06.14 22:36 
Hallo,

hin und wieder habe ich hier schon Hilfe bekommen. Ich schätze dieses Forum auch wegen des tollen Supports. Eben gerade war mein Account noch gesperrt. Zwei Minuten später hatte ich schon die Lösung von euch (:-)@entwickler-ecke.de) im Postfach.

Aber nun zu meinem Problem. Ich möchte Daten aus einer strukturierten Textdatei lesen und die Datensätze (jeweils eine Zeile) in ein TObjekt-Descendent speichern. In den Daten gibt es zwei Felder welche den Datentyp angeben und ob dieser einfach oder mehrfach (Liste) vorkommt. Mit meinen eigenen Kenntnissen komme ich da leider nicht weiter. Deshalb gibt's dazu auch kein Quelltext von mir. Ich habe nur eine wage Idee, dass man dazu eventuell procedurale Typen verwenden könnte.
Hätte vielleicht jemand ein Beispiel oder eine Quelle für den aha-Effekt für mich.

MfG
mandras
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 430
Erhaltene Danke: 107

Win 10
Delphi 6 Prof, Delphi 10.4 Prof
BeitragVerfasst: So 29.06.14 22:54 
Auf die Schnelle zusammengebastelt, ich weiß ja nicht viel über das was Du vorhast:

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:
uses Contnrs;

type TEintrag = class(TObject)
 A: string;
 B: integer;
end;

procedure TForm1.Button1Click(Sender: TObject);
var DieListe: TObjectList;
    NeuEintrag: TEintrag;
    EinEintrag : TEintrag;
begin
 DieListe := TObjectList.Create;
 NeuEintrag := TEintrag.Create;
 NeuEintrag.A := 'Hallo';
 NeuEintrag.B := 17;
 // Eintrag hinzufügen
 DieListe.Add(NeuEintrag);
 // Eintrag holen
 EinEintrag := DieListe[0as TEintrag;
 Application.MessageBox(pchar(format ('Eintrag: %s Wert: %d',[EinEintrag.A,EinEintrag.B])),'Ergebnis');

end;
ml-kuen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
BeitragVerfasst: So 29.06.14 23:20 
Danke für die Antwort,

hab mich offenbar nicht richtig ausgedrückt. Die Textdatei hat unter anderem fogende Struktur:

ausblenden Quelltext
1:
2:
3:
4:
... Add Optiondef 2 "Time Offset" DWORD 0 comment="UCT offset in seconds" 0
... Add Optiondef 3 "Router" IPADDRESS 1 comment="Array of router addresses ordered by preference" 0.0.0.0
...
... Add Optiondef 17 "Root Path" STRING 0 comment="Path name for client's root disk, char set NVT ASCII" ""


es handelt sich um einen Auszug eines DHCP-Server-Dumps (netsh dhcp \\server dump).

Im Feld 0 und 1 steht, dass eine Optionsdefinition hinzugefügt wird.
Im Feld 2 steht die Options-ID.
Im Feld 3 steht der Name der Option.
Im Feld 4 steht der Datentyp des letzten/der letzten Felder.
Im Feld 6 steht ein Kommentar
Im Feld 5 steht, ob die Daten Einzelwerte (0) oder Mehrfache Werte (1) sind.

Vorkommende Datentypen sind: 'BINARY', 'BYTE', 'WORD', 'DWORD', 'IPADDRESS' und 'STRING'.

Nun sollten hoffentlich alle Klarheiten beseitigt sein :wink:


Zuletzt bearbeitet von ml-kuen am Mo 30.06.14 21:50, insgesamt 1-mal bearbeitet
freak4fun
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 604
Erhaltene Danke: 4

Win 7 Pro
VS 2013 Express, Delphi, C#, PHP, Java
BeitragVerfasst: So 29.06.14 23:34 
Datei Zeilenweise einlesen oder auch in StringList(StrictDelimiter), dann anhand eines Trennzeichens (" ") den String teilen und die einzelnen Segmente entsprechend behandeln. ;)

_________________
"Ich werde auf GAR KEINEN Fall…!" - "Keks?" - "Okay, ich tu's."
i++; // zaehler i um 1 erhoehen
ml-kuen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
BeitragVerfasst: So 29.06.14 23:41 
Hallo user profile iconfreak4fun,

hast du dir die Frage wirklich durchgelesen? Langsam zweifle ich...
ssb-blume
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 375
Erhaltene Danke: 7

XP, W7, W8
Deutschland
BeitragVerfasst: Mo 30.06.14 09:08 
Zuerst je Zeile den Text mit "..." suchen und löschen. Dann wie freak4fun beschrieben Rest mit stringparse (weiß nicht, wie in Delphi das heist) mit den Leerzeichen teilen, in dem erzeugten Array stehen dan die gesuchten werte.
Hansi

_________________
Brain: an apparatus with which we think we think.
Quitzlinga
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 60
Erhaltene Danke: 2

Win XP
Delphi 2007 Prof. Codegear Win32
BeitragVerfasst: Mo 30.06.14 09:18 
Hi,

evt. hilft Dir für die Abbildung ein Suche bei Google VARIANTER RECORD weiter.
Ansonsten würde ich es folgendermassen machen:

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:
type TOptionDatatype = (optBINARY, optBYTE, optWORD, optDWORD, optIPADDRESS, optSTRING);

type TOption = class(TObject)
    ID : integer;
    OName : string;
    Datatype : TOptionDatatype;
    Data : TObjectlist;
    Einzelwerte : boolean;
    Kommentar : string;
  private
  public
    constructor Create();overload;
    destructor Destroy();override
end;

type TOptionList = class(TObjectList)
  private
  public
    function LoadFromFile(aFilename : string) : boolean;
end;

constructor TOption.Create();
begin
  inherited Create();
  Data := TObjectlist.Create();
end;

destructor TOption.Destroy();
begin
  FreeAndNil(Data);
  inherited Destroy();
end;

function TOptionList.LoadFromFile(aFilename : string) : boolean;
begin
  // File zeilenweise einlesen und die TOptionObjekte entsprechend befüllen
end;


MfG

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



BeitragVerfasst: Mo 30.06.14 09:43 
Eine varianten Record hatte ich auch gleich im Hinterkopf:
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:
type
  TMyDataType = (dtWord, dtDWord, dtString);
  TMyData = record
    DataType: TMyDataType;
    case integer of
      0:( WordData: Word );
      1:( DWordData: DWord );
      2:( StringData: Shortstring );
  end;

procedure ShowData(const Data: TMyData);
begin
  case Data.DataType of
    dtWord:
      ShowMessage(Format('Die Worddaten enthalten %d.', [Data.WordData]));
    dtDWord:
      ShowMessage(Format('Die DWorddaten enthalten %d.', [Data.DWordData]));
    dtString:
      ShowMessage(Format('Die Stringdaten enthalten "%s".', [Data.StringData]));
  end;
end;

procedure TFormTest.Button1Click(Sender: TObject);
var
  Data: array[0..2of TMyData;
  i: integer;
begin
  Data[0].DataType := dtWord;
  Data[0].WordData := 65535;
  Data[1].DataType := dtDword;
  Data[1].DWordData := 42;
  Data[2].DataType := dtString;
  Data[2].StringData := 'Hallo Welt';
  for i := Low(Data) to High(Data) do
    ShowData(Data[i]);
end;
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 43



BeitragVerfasst: Mo 30.06.14 11:04 
Ich vermute das Grundwissen fehlt, wie man so einen Text erst mal zerlegt.
Die Objektstruktur, in die diese Daten überführt werden sollen, ist noch mal eine andere Baustelle.
Ungetestet ein kleines Beispiel:
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:
const
  CRLF = #13#10;

type
  TZeileObject = class(TObject)
  private
    FComment: string;
  published
    property Comment: string read FComment write FComment;
  end;

  TTimeOffsetObject = class(TZeileObject)
  private
    FValue: DWord;
  published
    property Value: DWord read FValue write FValue;
  end;

procedure CheckSpalte(ASpalte: Integer; Spalten: TStringList; const ACheckValue: string);
begin
  if Spalten[ASpalte] <> AValueFound then
    raise Exception.CreateFmt('Ungültiger Wert in Spalte %d erwartet "%s" gefunden "%s".'
                              [ASpalte + 1, ACheckValue, Spalten[ASpalte]]);
end;

procedure ImportTyp2(Spalten: TStringList; AItemList: TObjectList);
var
  lData: TTimeOffsetObject;
begin
  lData := nil;
  try
    if Spalten.Count < 8 then
      raise Exception.CreateFmt('Spaltenanzahl(%d) zu gering', [Spalten.Count]);

    CheckSpalte(3, Spalten, 'Time Offset');
    CheckSpalte(4, Spalten, 'DWORD');
    CheckSpalte(5, Spalten, '0');

    lData := TTimeOffsetObject.Create;
    lData.Comment := Spalten.Values['comment'];
    lData.Value   := StrToInt(Spalten[7];);
  except
    on E: Exception do
    begin
      lData.Free;
      E.Message := Format('ImportTyp2' + CRLF) + E.Message;
      raise;
    end;
  end;
  AItemList.Add(lDate);    
end;

procedure ImportFile(const AFilename: string; AItemList: TObjectList);
var
  Zeilen, Spalten: TStringList;
  iZeile: Integer;
begin
  Zeilen  := nil;
  Spalten := nil;
  try
    Zeilen  := TStringList.Create;
    Zeilen.LoadFromFile(AFilename);

    Spalten := TStringList.Create;
    Spalten.QuoteChar := '"';
    Spalten.Delimiter := ' ';
    Spalten.StrictDelimiter := True;

    for iZeile := Low(Zeilen) to High(Zeilen) do
    begin
      try
        Spalten.DelimitedText := Zeilen[iZeile];
        case Spalten.Count of
          0:    Continue; // Leerzeilen ignorieren
          1..5raise Exception.CreateFmt('Spaltenanzahl(%d) zu gering', [Spalten.Count]);
        end;

        case IntToStrDef(Spalten[2], -1of
          2: ImportTyp2(Spalten, AItemList);
          3: ImportTyp3(Spalten, AItemList);
         17: ImportTyp17(Spalten, AItemList);
        else
          raise Exception.CreateFmt('Spalte 3 ImportTyp ''%s'' ist nicht definiert', [Spalten[2]]);
        end;

      except
        on E: Exception do
        begin
          E.Message := Format('Import-Fehler in Zeile %d' + CRLF, [iZeile + 1]) + E.Message;
          raise;
        end;
      end;    
    end;
  finally
    Spalten.Free;
    Zeilen.Free;
  end;
end;
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Mo 30.06.14 11:14 
Also, ich lese aus der Frage heraus, dass es nicht um Stringzerlegung geht, sondern darum, verschiedene Datentypen möglichst einheitlich zu handlen.
ml-kuen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
BeitragVerfasst: Mo 30.06.14 21:18 
Vielen Dank user profile iconWasWeißDennIch, endlich hat jemand gecheckt was ich möchte. Wie man die String-Zeile zerlegt weiß ich und das ist auch nicht das Problem. Allerdings sind es viele verschiedene Datentypen und die Werte sind manchmal als Liste zu speichern. Die Textzeilen (siehe oben) sind halt nur eine Definition der Werte die dann weiter unten in der Datei noch kommen. Identifiziert werden die zugehörigen Werte dort durch die Options-ID (siehe oben).
Die Wertezeilen sehen etwa so aus:

ausblenden Quelltext
1:
2:
3:
... set optionvalue  2 DWORD 3600
... set optionvalue  3 IPADDRESS 192.168.0.1 192.168.0.254
... set optionvalue 17 STRING "\\rechnername.domain.net\Freigabe"


Beispielsweise ist die Optionvalue 2 der Time- Offset. Da dieser Wert nur einmal vorkommen kann steht im Feld 5 auch eine 0 (einzelner Wert).
In der nächsten Zeile ist die Optionvalue 3 und damit von der Definition (siehe oben) die Routeradresse. Da es davon bekanntlich mehrere geben kann, steht in der Definition oben auch eine 1 im Feld 5. Optionvalue 17 ist wieder ein Einzelwert im String-Format... usw. Es können bis zu 255 Optionen existieren.

Ich möchte nun aber nicht für jede Kombination von Datentyp und Wertehäufigkeit ein eigenes Objekt erstellen - wenn's möglich ist. Vermutlich muss ich wohl doch einen Varianten Typ in eine Liste stecken, welche dann beides beherrscht. Einen oder mehrere Werte von einem Typ, den Variant halt zulässt. IPADDRESS ließe sich in DWORD verstecken, Strings in Strings und die anderen fundamentalen Typen sollten mit Variant auch funktionieren.

Gibt's, abgesehen von Variant, noch andere Möglichkeiten?

Gruß
icho2099
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 101
Erhaltene Danke: 12

WIN XP, WIN 7, WIN 10
Delphi 6 Prof, Delphi 2005, FPC
BeitragVerfasst: Di 01.07.14 00:11 
Ich würde es bei den Strings belassen und diese zusammen mit den Type-defs in eine stringliste
schreiben. Alle Datenfelder einer Zeile sind doch vom gleichen Typ.
Was willst du denn mit den so gewonnenen Daten dann noch tun?
ml-kuen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17

Win 95, Win 98, Win 2000, Win XP, Win 7
Delphi 7 personal
BeitragVerfasst: Di 01.07.14 00:46 
Hallo user profile iconicho2099,

mit IP-Adressen kann man rechnen - Anzahl Hosts in einem Subnet - nächste freie IP herausfinden und und und. Mit den anderen Datentypen ausser String selbverständlich auch. Die Sortierung einer IP oder Zahl ist auch anders als die alphabetische.
Du hast ja Recht, wenn du mit deiner Anregung meinst, man sollte nicht "mit Kanonen auf Spatzen schießen". Leider musste ich aber schon oft feststellen, dass sich diese herangehensweise bei einer objektorientierten Programmieraufgabe irgendwann rechen kann. Ich bin ja nur ein Hobby-Programmierer und tue dies aus Interesse und Freude am verstehen. Natürlich soll auch etwas sinnvolles dabei rauskommen. Aber anders als bei einem Profi mit Pflichtenheft usw. wächst bei mir das Programm manchmal im Kopf weiter und man hat Spaß dabei die Dinge weiterzuspinnen.

Gruß