Dateien parsen - mit welchen Werkzeugen ?
-
- Beiträge: 478
- Registriert: Fr 13. Sep 2013, 12:07
- OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
- CPU-Target: 64Bit
- Wohnort: Rügen
Re: Dateien parsen - mit welchen Werkzeugen ?
Hallo mse,
dein Tipp die Stringlist in einen string zu pumpen war der entscheidende Faktor.
Nun dauert es statt einer Minute nur noch eine knappe sekunde - das ist ja krass
Hallo braunbär,
Danke für das Beispiel - nun ist mir auch klar wie man im Programm mit regex umgeht.
Ich werde das heute noch ausprobieren. Der Code wird ja sehr übersichtlich
Den regex Ausdruck zu bauen ist als ungeübter jedoch eine herausforderung.
Mit den globalen Var ist mir bekannt - bei einer Function bekomme ich jedoch nur einen Wer zurück - ok man kann auch eine Array zurückgeben.
OOP klassen bauen mag ich nicht so gern - Proprerty 's kann man die auch ohne klassen verwenden ?
Gruß
Frank
dein Tipp die Stringlist in einen string zu pumpen war der entscheidende Faktor.
Nun dauert es statt einer Minute nur noch eine knappe sekunde - das ist ja krass
Hallo braunbär,
Danke für das Beispiel - nun ist mir auch klar wie man im Programm mit regex umgeht.
Ich werde das heute noch ausprobieren. Der Code wird ja sehr übersichtlich
Den regex Ausdruck zu bauen ist als ungeübter jedoch eine herausforderung.
Mit den globalen Var ist mir bekannt - bei einer Function bekomme ich jedoch nur einen Wer zurück - ok man kann auch eine Array zurückgeben.
OOP klassen bauen mag ich nicht so gern - Proprerty 's kann man die auch ohne klassen verwenden ?
Gruß
Frank
Re: Dateien parsen - mit welchen Werkzeugen ?
DL3AD hat geschrieben: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.
Hier findest du eine Version deines Parsers, die mit PChar arbeitet, und die wird in knapp 0.2 Sekunden fertig.
Code: Alles auswählen
procedure GetAdifValue(var p: PChar);
var
n : integer;
Vlng: string;
begin
n := 0;
ATag := '';
AValue:= '';
Vlng := '';
while p^ <> #0 do // Wenn Zeichen nicht das abschließende Null-Byte...
begin
if p^ = '<' then
begin // Hier stehen wir auf den '<'
inc(p);//nächstes Zeichen und weiter zum Tagende, oder ein ':' kommt
while (p^ <> #0) and (p^ <> ':') and (p^ <> '>') do
begin
ATag:= ATag + p^;//gefundenes Zeichen Tag zuordnen
ATag:= Upcase(ATag);
inc(p);// Zum nächsten Zeichen.
end;
//Jetzt sind wir auf dem ':' oder haben das Tagende erreicht.
if p^ = #0 then
exit;//Fall 1) StringEnde --> raus
if p^ = ':' then//Fall 2) Wir stehen auf dem ':'
begin
inc(p);
while (p^ <> #0) and (p^ <> '>') do
begin
Vlng:= Vlng + p^;
inc(p);
end;//Jetzt sind wir auf dem '>' und haben das Tagende erreicht
n:= StrToInt(Vlng);//Länge Adif Value in Interger wandeln
inc(p);
end else
inc(p);
while (p^ <> #0) and (n > 0) do
begin
AValue:= AValue + p^;//Adif Value Zeichen aufaddieren
dec(n);
inc(p);//Von '>' weiter aud das erste Zeichen vom Adif Value
end;
if n = 0 then
exit;
end;
inc(p);
end;
end;
//Daten einlesen
procedure TForm1.Button1Click(Sender: TObject);
var
t: TDateTime;
s: String;
p: PChar;
begin
t := now;
s := AFile.Text;
p := @s[1];
while p^ <> #0 do //Ai < Length(s) do
begin
ClearVar;
while (ATag <> 'EOR') and (p^ <> #0) do
begin
ADIFPars.GetAdifValue(p);
Case ADIFPars.ATag of
'CALL' : ACALL := ADIFPars.AValue;
'QTH' : AQTH := ADIFPars.AValue;
'NAME' : ANAME := ADIFPars.AValue;
'TIME_ON' : ATIME_ON := ADIFPars.AValue;
'QSO_DATE' : AQSO_DATE := ADIFPars.AValue;
'RST_SENT' : ARST_SENT := ADIFPars.AValue;
'RST_RCVD' : ARST_RCVD := ADIFPars.AValue;
'BAND' : ABAND := ADIFPars.AValue;
'FREQ' : AFREQ := ADIFPars.AValue;
'MODE' : AMODE := ADIFPars.AValue;
'CONT' : ACONT := ADIFPars.AValue;
'ITUZ' : AITUZ := ADIFPars.AValue;
'CQZ' : ACQZ := ADIFPars.AValue;
'DXCC' : ADXCC := ADIFPars.AValue;
'COUNTRY' : ACOUNTRY := ADIFPars.AValue;
'GRIDSQUARE' : AGRIDSQUARE := ADIFPars.AValue;
'IOTA' : AIOTA := ADIFPars.AValue;
'STATE' : ASTATE := ADIFPars.AValue;
'QSL_RCVD' : AQSL_RCVD := ADIFPars.AValue;
'LOTW_QSL_RCVD': ALOTW_QSL_RCVD:= ADIFPars.AValue;
'EQSL_QSL_RCVD': AEQSL_QSL_RCVD:= ADIFPars.AValue;
'COMMENT' : ACOMMENT := ADIFPars.AValue;
'PFX' : APFX := ADIFPars.AValue;
'EOR' : ChData;
end;
inc(p);
end;
ATag:= '';
end;
ShowMessage('Fertig! (' + FormatDateTime('s.zzz', now-t) + ' s)');
end;
P.S.
Noch zu einem möglichen Problem: In der ADIF-Doc, die ich weiter oben zitiert habe, steht, dass hinter der Längenangabe im Tag noch eine Datentyp-Angabe kommen kann, z.B. <qso_date:8:d>. Das bedeutet, dass die Längenangabe in diesem Code nicht richtig ausgelesen wird. Du findest sicher, wie das abzuändern ist.
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2640
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Dateien parsen - mit welchen Werkzeugen ?
DL3AD hat geschrieben:Mit den globalen Var ist mir bekannt - bei einer Function bekomme ich jedoch nur einen Wer zurück - ok man kann auch eine Array zurückgeben.
OOP klassen bauen mag ich nicht so gern - Proprerty 's kann man die auch ohne klassen verwenden ?
Du kannst auch records verwenden um mehrere Werte in einer Struktur zurückzugeben.
Properties ohne Klassen gibt es auch, das ist aber etwas anderes.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10: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
Re: Dateien parsen - mit welchen Werkzeugen ?
wp_xyz hat geschrieben:P.S.
Noch zu einem möglichen Problem: In der ADIF-Doc, die ich weiter oben zitiert habe, steht, dass hinter der Längenangabe im Tag noch eine Datentyp-Angabe kommen kann, z.B. <qso_date:8:d>. Das bedeutet, dass die Längenangabe in diesem Code nicht richtig ausgelesen wird. Du findest sicher, wie das abzuändern ist.
Und die Felder können binäre Daten enthalten.
Code: Alles auswählen
while (p^ <> #0) and (n > 0) do //#0 kann in binären daten vorkommen.
begin
AValue:= AValue + p^;//Adif Value Zeichen aufaddieren
ist nicht zuverlässig. Es wäre auch schneller AValue auf einmal zu laden und nicht Zeichen für Zeichen.
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: Dateien parsen - mit welchen Werkzeugen ?
DL3AD hat geschrieben:Den regex Ausdruck zu bauen ist als ungeübter jedoch eine herausforderung.
Das stimmt, am Anfang bin ich bei jedem Regex eine ganze Weile gesessen. Aber es zahlt sich wirklich aus, da in etwas Übung zu investieren, die Programme werden um ein Vielfaches einfacher, und, wenn man die einzelnen Teile des Regex entsprechend kommentiert, auch viel leichter verständlich als die unzähligen Schleifen eines spezialisierten Parsers.
DL3AD hat geschrieben:bei einer Function bekomme ich jedoch nur einen Wer zurück - ok man kann auch eine Array zurückgeben.
Vor allem brauchst du hier keine Function - mach eine procedure mit einem var-Parameter und zwei out-parametern. Struktur brauchst du da gar keine.
Code: Alles auswählen
procedure ScanAdif(var s: String; out aTag, aValue: string);
Zuletzt geändert von braunbär am Mo 10. Jul 2017, 13:58, insgesamt 1-mal geändert.
-
- Beiträge: 478
- Registriert: Fr 13. Sep 2013, 12:07
- OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
- CPU-Target: 64Bit
- Wohnort: Rügen
Re: Dateien parsen - mit welchen Werkzeugen ?
Hallo wp_xyz,
Danke für die Analyse meines Problemes.
Hatte vorhin die Stringlist ein eine string geladen - dann ging es auch rasent schnell - habe mal die Zeitmessung eingebaut und auf meinem alten Bürorechner CoreI3 sind es 0,218s
Hallo braunbär,
Das mit out kannte ich noch garnicht - seit wann gibt es dass ?
Das werde ich heute auch mal testen und den Code entsprechen umbauen - dann sich funktionen ja qusai obsolett.
Gruß
Frank
Danke für die Analyse meines Problemes.
Hatte vorhin die Stringlist ein eine string geladen - dann ging es auch rasent schnell - habe mal die Zeitmessung eingebaut und auf meinem alten Bürorechner CoreI3 sind es 0,218s
Hallo braunbär,
Code: Alles auswählen
procedure ScanAdif(var s: String; out aTag, aValue: string);
Das mit out kannte ich noch garnicht - seit wann gibt es dass ?
Das werde ich heute auch mal testen und den Code entsprechen umbauen - dann sich funktionen ja qusai obsolett.
Gruß
Frank
Re: Dateien parsen - mit welchen Werkzeugen ?
Hab jetzt auch ALLE StringList.Text durch einen String ersetzt, und komme auf dieselbe Zeit wie bei der PChar-Variante (vorher hatte ich einige übersehen) -> auf PChar umzustellen lohnt sich nicht, v.a. wenn dir PChar suspekt ist.
-
- Beiträge: 369
- Registriert: Do 8. Jun 2017, 18:21
- OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
- CPU-Target: 64Bit
- Wohnort: Wien
Re: Dateien parsen - mit welchen Werkzeugen ?
DL3AD hat geschrieben:dann sich funktionen ja quasi obsolet.
Obsolet sind sie nicht, weil du nur Funktionen direkt in einem Ausdruck verwenden kannst. Eine function, die nur einen Wert berechnet, ist in der Verwendung schon um einiges praktischer als eine procedure.
DL3AD hat geschrieben:Das mit out kannte ich noch garnicht - seit wann gibt es dass ?
Schon recht lange. Aber in Turbo Pascal gab es das noch nicht, wenn ich mich richtig erinnere.
Im Grunde genommen ist out nichts anderes als var, bloss dass der Compiler (und vor allem auch der, der den Code liest) weiss, dass die Werte, die beim Start der Prozedur in der Variable stehen, nicht verwendet werden. Der Compiler kann eine Warnung ausgeben, wenn du in der Prozedur den Wert der Variablen verwendest, ohne der Variablen in der Prozedur vorher einen Wert zuzuweisen.
Und wenn du eine Prozedur mit so einer Signatur benützt, weisst du, dass du diese Variablen vor dem Prozeduraufruf nicht initialisieren brauchst.
-
- Beiträge: 478
- Registriert: Fr 13. Sep 2013, 12:07
- OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
- CPU-Target: 64Bit
- Wohnort: Rügen
Re: Dateien parsen - mit welchen Werkzeugen ?
... und ich komme noch aus der Generation Turbo Pascal.
Ich habe es gerade probiert es tatsächlich sehr praktisch mit out
Ich habe es gerade probiert es tatsächlich sehr praktisch mit out
Re: Dateien parsen - mit welchen Werkzeugen ?
mse hat geschrieben:Und die Felder können binäre Daten enthalten.
Stimmt! Dann wäre es von vornhinein sinnvoller, die Datei binär in ein Array of byte einzulesen und auf alle Stringfunktionen zu verzichten. Nicht dass FPC/Lazarus da plötzlich unbemerkt irgendwelche Codeseiten-Anpassungen und UTF8-Konvertierungen vornehmen...
-
- Beiträge: 6207
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Dateien parsen - mit welchen Werkzeugen ?
TStringlist.text ist eine sehr teure Operation da dort der String immer aus allen Zeilen zusammengesetzt wird.
Das sieht man seht gut, wen man die Source von TStringList.Text anguckt.
Code: Alles auswählen
Function TStrings.GetTextStr: string;
Var P : Pchar;
I,L,NLS : Longint;
S,NL : String;
begin
CheckSpecialChars;
// Determine needed place
if FLineBreak<>sLineBreak then
NL:=FLineBreak
else
Case FLBS of
tlbsLF : NL:=#10;
tlbsCRLF : NL:=#13#10;
tlbsCR : NL:=#13;
end;
L:=0;
NLS:=Length(NL);
For I:=0 to count-1 do
L:=L+Length(Strings[I])+NLS;
if SkipLastLineBreak then
Dec(L,NLS);
Setlength(Result,L);
P:=Pointer(Result);
For i:=0 To count-1 do
begin
S:=Strings[I];
L:=Length(S);
if L<>0 then
System.Move(Pointer(S)^,P^,L);
P:=P+L;
if (I<Count-1) or Not SkipLastLineBreak then
For L:=1 to NLS do
begin
P^:=NL[L];
inc(P);
end;
end;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 478
- Registriert: Fr 13. Sep 2013, 12:07
- OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
- CPU-Target: 64Bit
- Wohnort: Rügen
Re: Dateien parsen - mit welchen Werkzeugen ?
Hallo,
nun läuft es recht fluffig knappe 0,4s um die Daten zu parsen und in die ZQuery zu schreiben dass ist absolut OK
ABER nach ApplyUpdates also dass die Query die Daten in die Datenbank schaufelt dauert immerhin noch 8s für 2500 Datensätze mit 28 Feldern je Datensatz.
Nun kann ich es nicht einschätzen ob dass OK ist oder das zu lange dauert für eine sqlite3 DB.
Gruß
Frank
nun läuft es recht fluffig knappe 0,4s um die Daten zu parsen und in die ZQuery zu schreiben dass ist absolut OK
ABER nach ApplyUpdates also dass die Query die Daten in die Datenbank schaufelt dauert immerhin noch 8s für 2500 Datensätze mit 28 Feldern je Datensatz.
Nun kann ich es nicht einschätzen ob dass OK ist oder das zu lange dauert für eine sqlite3 DB.
Gruß
Frank
- af0815
- Lazarusforum e. V.
- Beiträge: 6213
- Registriert: So 7. Jan 2007, 10:20
- OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
- CPU-Target: 32Bit (64Bit)
- Wohnort: Burgenland
- Kontaktdaten:
Re: Dateien parsen - mit welchen Werkzeugen ?
DL3AD hat geschrieben:ABER nach ApplyUpdates also dass die Query die Daten in die Datenbank schaufelt dauert immerhin noch 8s für 2500 Datensätze mit 28 Feldern je Datensatz.
Nun kann ich es nicht einschätzen ob dass OK ist oder das zu lange dauert für eine sqlite3 DB.
Hängt davon ab wie die DB/Verbindung konfiguriert ist und wie sicher deine Daten sein sollen. Ich habe dazu schon mal Versuche gemacht, damals mit JSON in die DB schreiben, da geht schon was wenn man es darauf anlegt. Ist aber eine Abwägungssache zwischen Geschwindigkeit und Sicherheit.
Siehe JSON Array in Datenbanktabelle hier im Forum.
Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
-
- Beiträge: 2013
- Registriert: Do 16. Okt 2008, 10: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
Re: Dateien parsen - mit welchen Werkzeugen ?
DL3AD hat geschrieben:nun läuft es recht fluffig knappe 0,4s um die Daten zu parsen und in die ZQuery zu schreiben dass ist absolut OK
ABER nach ApplyUpdates also dass die Query die Daten in die Datenbank schaufelt dauert immerhin noch 8s für 2500 Datensätze mit 28 Feldern je Datensatz.
Siehe meine Bemerkung zu den Transaktionen. CachedUpdates bringen auch nur unnötigen overhead.
Zum Vergleich, mit tsqlstatement von MSEgui komme ich für 2500 records auf 0.2 Sekunden.
Das Projekt ist hier:
https://gitlab.com/mseide-msegui/mseuni ... ertrecords
Ist es OK deine DB mit leerer Log Tabelle dort zu platzieren?