Dateien parsen - mit welchen Werkzeugen ?

Für Fragen von Einsteigern und Programmieranfängern...

Re: Dateien parsen - mit welchen Werkzeugen ?

Beitragvon DL3AD » 9. Jul 2017, 16:05 Re: Dateien parsen - mit welchen Werkzeugen ?

Hallo,

ich habe nun eine Lösung fertig (Zeichen für Zeichen analysieren) funktioniert super aaaaber - dauer elendig lange.

Nun möchte ich noch eine andere Variante probieren - Regex ? wüste leider nicht wie ich da anfangen sollte.
Dann hatte ich mit Stringlist und Delimeter (<) probiert - es wird der String zwar zerhackt aber auch nach einen Leerzeichen und dass ist mist.

Git es irgendwo ein Beispiel wie man mit den Regex umgeht ?
Oder git es noch einen anderen Ansatz ?

Gruß
Frank
DL3AD
 
Beiträge: 368
Registriert: 13. Sep 2013, 11:07
Wohnort: Rügen
OS, Lazarus, FPC: Win7 (L 1.8.0 FPC 3.0.4) und Debian Stretch (L 1.8.0 FPC 3.0.4) | 
CPU-Target: 32Bit/64Bit
Nach oben

Beitragvon wp_xyz » 9. Jul 2017, 16:10 Re: Dateien parsen - mit welchen Werkzeugen ?

Such doch zuerst den Fehler in deinem aktuellen Ansatz, bevor du dich in ein neues Abenteuer stürzt. Der von mir vorgestellte Algorithmus ist garantiert schnell. Wahrscheinlich schreibst du die extrahierten Strings in visuelle Controls, die sich bei jeder Änderung neu ausgeben. Um mehr sagen zu können, müsste ich deinen Code kennen.
wp_xyz
 
Beiträge: 2569
Registriert: 8. Apr 2011, 08:01

Beitragvon DL3AD » 9. Jul 2017, 16:33 Re: Dateien parsen - mit welchen Werkzeugen ?

... hier die Procedure die mir einen Tag und Tagvalue extrahiert

Code: Alles auswählen
//ADIF Tag und Tag Value ermitteln
procedure GetAdifValue(Txt: string);
var
  n   : integer;
  Vlng: string;
begin
  n     := 0;
  ATag  := '';
  AValue:= '';
  Vlng  := '';
  while Ai <= Length(Txt) do //Wenn index kleiner als Textlänge
  begin
    if Txt[Ai] = '<' then
      begin // Hier stehen wir auf den '<'
        inc(Ai);//nächstes Zeichen und weiter zum Tagende, oder ein ':' kommt
        while (Ai <= Length(Txt)) and  (Txt[Ai] <>':') and (Txt[Ai] <> '>') do
          begin
            ATag:= ATag + Txt[Ai];//gefundenes Zeichen Tag zuordnen
            ATag:= Upcase(ATag);
            inc(Ai);// Zum nächsten Zeichen.
          end;//Jetzt sind wir auf dem ':' oder haben das Tagende erreicht.
          if Ai > Length(Txt) then exit;//Fall 1) StringEnde --> raus
          if Txt[Ai] = ':' then//Fall 2) Wir stehen auf dem ':'
            begin
              inc(Ai);
              while (Ai <= Length(Txt)) and (Txt[Ai] <> '>') do
                begin
                  Vlng:= Vlng + Txt[Ai];
                  inc(Ai);
                end;//Jetzt sind wir auf dem '>' und haben das Tagende erreicht
              n:= StrToInt(Vlng);//Länge Adif Value in Interger wandeln
            end;
              while (Ai <= Length(Txt)) and (n > 0) do
              begin
                inc(Ai);//Von '>' weiter aud das erste Zeichen vom Adif Value
                AValue:= AValue + Txt[Ai];//Adif Value Zeichen aufaddieren
                dec(n);
              end;
              inc(Ai);//Vom letzen Zeichen des Adif Value auf das nächse gehen
              if n = 0 then exit;
       end;
  inc(Ai);
  end;
end;
 


Die einzelnen TagValue werden über eine Case entsprechnden Variablen zugeordnet bis ein Datensatz komplett ist (wenn Tag <eor>) einige Tags werden auch verworfen weil sie nicht gebraucht werden.
Eine Ausgabe auf der GUI wird nicht gemacht sondern gleich in die DB auch ohne in DB schreiben dauert es.

Der Ansatz von Braunbär scheint recht interessant nur weis ich nicht wie man mit den Regexp umgehen kann .

Gruß
Frank
DL3AD
 
Beiträge: 368
Registriert: 13. Sep 2013, 11:07
Wohnort: Rügen
OS, Lazarus, FPC: Win7 (L 1.8.0 FPC 3.0.4) und Debian Stretch (L 1.8.0 FPC 3.0.4) | 
CPU-Target: 32Bit/64Bit
Nach oben

Beitragvon Mathias » 9. Jul 2017, 16:39 Re: Dateien parsen - mit welchen Werkzeugen ?

ich habe nun eine Lösung fertig (Zeichen für Zeichen analysieren) funktioniert super aaaaber - dauer elendig lange.

Wieso sollte dies sehr lange dauern, eigentlich müsste dies die schnellste Lösung sein.
Alle anderen Funktion Splitt, Pos, etc. machen im Hintergrund nichts anderes, habe aber viel Overhead, da sie universell sind.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4107
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon mse » 9. Jul 2017, 16:56 Re: Dateien parsen - mit welchen Werkzeugen ?

DL3AD hat geschrieben:Eine Ausgabe auf der GUI wird nicht gemacht sondern gleich in die DB auch ohne in DB schreiben dauert es.

Falls du in Sqlite3 schreibst sollten die Records in einer gemeinsamen Transaktion geschrieben werden, sonst wird bei jedem INSERT gesynct und das ist langsam.
mse
 
Beiträge: 1949
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon DL3AD » 9. Jul 2017, 17:22 Re: Dateien parsen - mit welchen Werkzeugen ?

Hallo mse,

Danke für den Tip - das hatte ich leider nicht gemacht.

Code: Alles auswählen
Query.insert;
.
.
.
Query.post;
Query.applyupdates;


Wie macht man es den anders ?

Gruß Frank
DL3AD
 
Beiträge: 368
Registriert: 13. Sep 2013, 11:07
Wohnort: Rügen
OS, Lazarus, FPC: Win7 (L 1.8.0 FPC 3.0.4) und Debian Stretch (L 1.8.0 FPC 3.0.4) | 
CPU-Target: 32Bit/64Bit
Nach oben

Beitragvon wp_xyz » 9. Jul 2017, 17:49 Re: Dateien parsen - mit welchen Werkzeugen ?

Nochmals visuelle Controls: Hängen am Query visuelle DBControls? Ein DBGrid z.B.? Hier bringt Query.DisableControls vor und Query.EnableControls nach der gesamten Aktion Wunder.

Welche Datenbank?

Ein Tipp zum Prüfen, ob GetADIFValue der Sündenbock ist: Kommentiere einmal den Zugriff auf die Datenbank aus, so dass GetADIF Value die gefundenen Daten ins Leere schreibt. Das muss sehr schnell gehen. Wenn du das bestätigen kannst, sollte klar sein, dass RegEx auch nicht schneller sein kann.

Wenn nicht weiterhilft, müsstest du den gesamten Code posten.
wp_xyz
 
Beiträge: 2569
Registriert: 8. Apr 2011, 08:01

Beitragvon mse » 9. Jul 2017, 18:56 Re: Dateien parsen - mit welchen Werkzeugen ?

DL3AD hat geschrieben:Wie macht man es den anders ?

In MSEgui würde ich TSqlite3Connection.options slo_transactions aktivieren und die Daten mit einem TSQLStatement schreiben um den
TSQLQuery overhead zu vermeiden.
In Lazarus kannst du etwas entsprechendes mit TSQLQuery.ExecSQL() erreichen, eine SQL-Statement Komponente gibt es AFAIK mittlerweile auch. Die SQL-property muss ein SQL-INSERT-Statement enthalten, welches die Werte in die Datenbank schreibt. Etwa so:
Code: Alles auswählen
 
 while datenvorhanden do begin
  werte nächsten Record aus;
  speichere die Felddaten in die entsprechenden "<sqlquery>.Params" Items;
  <sqlquery>.execsql();
 end;
 <transaction>.commit();
 

Der implizite-Transaktions-Modus muss ausgeschaltet sein, damit nicht bei jedem execsql() commited wird. Wie das in FPC geht, weiss ich nicht.
Kennst du dich mit SQL-INSERT statements aus?
Wie lange dauert der Schreibvorgang? Bei wie vielen records?
mse
 
Beiträge: 1949
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon DL3AD » 10. Jul 2017, 07:48 Re: Dateien parsen - mit welchen Werkzeugen ?

... ich verwende die Zeos komponenten für meine sqlite3 DB
In der Query habe ich CachedUpdates aktiviert damit nicht sofort in die DB geschrieben wird und mit ApplayUpdates wird in die DB geschrieben.

Werde mal rumsuchen wie man das mit den Zeos lösen kann.
DL3AD
 
Beiträge: 368
Registriert: 13. Sep 2013, 11:07
Wohnort: Rügen
OS, Lazarus, FPC: Win7 (L 1.8.0 FPC 3.0.4) und Debian Stretch (L 1.8.0 FPC 3.0.4) | 
CPU-Target: 32Bit/64Bit
Nach oben

Beitragvon mse » 10. Jul 2017, 08:47 Re: Dateien parsen - mit welchen Werkzeugen ?

Vermutlich sollte TZConnection.AutoCommit auf "false" gesetzt werden.
mse
 
Beiträge: 1949
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon gladio » 10. Jul 2017, 08:58 Re: Dateien parsen - mit welchen Werkzeugen ?

Versuche es mal ohne ApplyUpdates. Das einfache Query.Post sollte reichen.
gladio
 
Beiträge: 95
Registriert: 21. Jun 2014, 05:15
Wohnort: Insel Rügen
OS, Lazarus, FPC: Win7/10-32/64 - Laz 1.8 Standard-Edition | 
CPU-Target: 32/64Bit
Nach oben

Beitragvon wp_xyz » 10. Jul 2017, 09:20 Re: Dateien parsen - mit welchen Werkzeugen ?

Nimm dir die Zeit und extrahiere die fraglichen Programmteile (parsen und in DB schreiben) in eine kleine Demo, so dass der Fehler reproduziert werden kann, und poste das Projekt zusammen mit der ADIF-Datei. Wahrscheinlich findest du dabei den Fehler schon von allein, oder du bekommst hier innerhalb kürzester Zeit konkrete Hinweise, was falsch ist. Sonst bleibt hier alles beim unverbindlichen Herumraten.
wp_xyz
 
Beiträge: 2569
Registriert: 8. Apr 2011, 08:01

Beitragvon DL3AD » 10. Jul 2017, 10:02 Re: Dateien parsen - mit welchen Werkzeugen ?

Hallo wp_xyz,

im Dateianhang ein Auszug aus dem Projekt.
Es ist nur das Parsen und zuordnen zu den DB Feldern ohne DB schreiben.
Es dauer ewig bis er fertig hat.
Die Adif mit ca 2500 Datensätzen ist auch dabei.

Gruß
Frank
Zuletzt geändert von DL3AD am 12. Jul 2017, 09:17, insgesamt 1-mal geändert.
DL3AD
 
Beiträge: 368
Registriert: 13. Sep 2013, 11:07
Wohnort: Rügen
OS, Lazarus, FPC: Win7 (L 1.8.0 FPC 3.0.4) und Debian Stretch (L 1.8.0 FPC 3.0.4) | 
CPU-Target: 32Bit/64Bit
Nach oben

Beitragvon braunbär » 10. Jul 2017, 10:11 Re: Dateien parsen - mit welchen Werkzeugen ?

Um es vorauszuschicken: Mit Regex wird das Parsing ziemich sicher nicht schneller. Ich denke aber, dass der Zeitverbrauch des Parsens bei deiner Aufgabe vernachlässigbar ist, egal, welches System du verwendest, Das Laufzeitproblem ist irgendwo anders begründet.
Der Vorteil von Regex liegt in der höheren Flexibilität, in der Einfacheit des Programms und in der Direktheit des Ansatzes. Statt einen Algorithmus zu programmieren, der die vorgegebene Syntax auflöst, schreibe ich ein Regex, dessen Komponenten nur beschreiben, wie der gesuchte String ausschaut. Um Details der Implementierung der Matchings brauche ich mich dann nicht zu kümmern, und wenn sich irgend wann an den Anforderugen etwas ändert, brauche ich nicht in Code wühlen, um zu finden, was ich jetzt in meinem Algorithmus anders machen muss, sondern ich brauche nur den regulären Ausdruck dort ändern, wo sich die Vorgabe geändert hat.

Code: Alles auswählen
 
uses
  RegExpr;
 
...
 
procedure GetAdifValue(var Txt: string);
const
regex =
   '(?i)'       // Case-insensitive
  +'^<'         // Der String muss mit dem Zeichen < anfangen
  +'(?:'        // Was hier innerhalb der Klammern folgt, ist als Submatch uninteressant. Die Klammern sind nur dazu da, um die beiden Alternativen zu klammern
  +'(eor)>\s*'  // 1. Alternative: Der Text eor>, wobei "eor" als erster Submatch gespeichert wird. Eventuelle Leerzeichen u.dgl. nach dem > werden ignoriert
  +'|'          // Hier endet die erste Alternative und beginnt die zweite Alternative
  +'([^:]+)'    // 1 oder mehr beliebige Zeichen bis zu einem ":" , wird im zweiten Submatch gespeichert
  +':'          // Dann ein Doppelpunkt
  +'([^>]+)'    // 1 oder mehr beliebige Zeichen bis zu einem ">" , wird im dritten Submatch gespeichert. Anzahl der Zeichen des Datenfelds   
  +'>'          // Das Zeichen >
  +'([^<]+)'    // 1 oder mehr beliebige Zeichen bis zu einem < oder dem Stringende, wird im vierten Submatch gespeichert,
                // eventuell statt dessen '(.{\3})\s*' probieren, wenn in den Daten das <-Zeichen vorkommen kann
  +')';         //  Schließt die Klammer von "(?:" - hier endet die zweite Alternative
 
var
re: TRegExpr;
begin
re := TRegExpr.Create(regex);
try
  if re.Exec(txt) then
  begin
   ATag:=upcase(trim(re.Match2));
   AValue:=upcase(trim(re.Match4));
   delete(txt,1,length(re.Match));
  end
  else showmessage('Syntax passt nicht: '+Txt);
  finally re.free;
end.
 


Die Prozedur schneidet aus dem String den gefundenen Teil heraus, sodass der nächste Prozeduraufruf richtig weitermacht.
Wenn der Tag eor gematcht wird, wird ein leerer Tag als ATag gesetzt (eor liegt in re.Match[1] und nicht in re.Match[2]).
Es wird alles in Upper Case konvertiert, wenn das bei den Daten unerwünscht ist, lass das upcase dort weg.
An sich gehören aTag und aValue als Prozedurparameter übergeben, globale Variable dafür zu nehmen ist prinzipiell keine gute Idee.

Eventuell wäre statt des Showmessage eine Exception angebracht, weil ja nicht sinnvoll weitergematcht werden kann.
Etwas effizienter wird es, wenn man das Regex nur einmal außerhalb dieser Prozedur erzeugt und erst ganz am Ende wieder freigibt.
Zuletzt geändert von braunbär am 10. Jul 2017, 10:56, insgesamt 2-mal geändert.
braunbär
 
Beiträge: 164
Registriert: 8. Jun 2017, 17:21

Beitragvon mse » 10. Jul 2017, 10:50 Re: Dateien parsen - mit welchen Werkzeugen ?

Probiere mal
Code: Alles auswählen
 
var
 s1: string;
begin
 s1:= AFile.Text;
  while Ai < Length(s1) do
  begin
    ClearVar;
    while (ATag <> 'EOR') and (Ai <= Length(s1)) do
      begin
        ADIFPars.GetAdifValue(s1);
        Case ADIFPars.ATag of
          'CALL'         : ACALL         := ADIFPars.AValue;
 

TStringlist.text ist eine sehr teure Operation da dort der String immer aus allen Zeilen zusammengesetzt wird. Wenn die Geschwindigkeit nicht reicht, gibt es noch viele weitere Optimierungsmöglichkeiten.
mse
 
Beiträge: 1949
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

» Weitere Beiträge siehe nächste Seite »
VorherigeNächste

Zurück zu Einsteigerfragen



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste

porpoises-institution
accuracy-worried