Konzept um mit einer Textdatei zu arbeiten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
power74
User
Beiträge: 14
Registriert: Donnerstag 3. September 2015, 12:25
Wohnort: in der Nähe von Zürich

Guten Tag Forum

Aus aktuellem Anlass geistert mir ein Projekt im Kopf rum:
Ich möchte eine Textdatei bearbeiten können mit Python3, die durch ein anderes Programm erstellt und auch ab und zu bearbeitet wird.
Der Grund ist der, dass das andere Programm relativ spezifisch für einen bestimmten Zweck gebraucht wird und die Bearbeitung dieser Datei eine Zweitfunktion ist. Ich möchte aber diese Datei auch ohne das ganze (andere) Programmpaket ab und zu bearbeiten können.
Mit Python3 könnte ich die Datei bequem auf allen PCs bearbeiten (Linux und Windows)

meine Probleme:
- ich kann nicht programmieren
- ich kann nicht python3 programmieren
- diese Datei ist ein Logbuch für Funkverbindungen, die Struktur ist gegeben - ich bin Funkamateur (ja genau, einer dieser komischen Kauze, die noch über Kurzwelle kommunizieren)
- ich bin manchmal ungeduldig, wenn ich mir etwas in den Kopf gesetzt habe

mein Vorteil:
- ich kann lesen
- ich kann "zuhören"
- ich kann nett fragen

Infos zu dieser Datei:
Die Datei ist im adif-Format, d.h. sie hat sogenannte Bezeichner mit Angabe der Anzahl Zeichen die im Datenbereich folgen und anschliessend einen Datenteil dazu. Also so: <FREQ:8>7.041271
Die Anzahl Bezeichner pro Record kann unterschiedlich sein, d.h. es kann vorkommen, dass ein Bezeichner mit <NOTES:> vorkommt oder auch nicht. An sich kann die Länge der Daten bei jedem Bezeichner unterschiedlich sein, ist ja irgendwie logisch... (z.B. NAME:)

Ein Datenrecord sieht so aus (anonymisiert):
[codebox=text file=Unbenannt.txt]<FREQ:8>7.041271<CALL:6>AB1CDE<MODE:5>PSK63<NAME:5>XXXXX<QSO_DATE:8>20170709<QSO_DATE_OFF:8>20170709<TIME_OFF:6>212515<TIME_ON:6>212200<QTH:5>Hieroderda<EQSLSDATE:8>20170711<GRIDSQUARE:6>JN00AB<BAND:3>40m<STATION_CALLSIGN:8>AB2FGH<MY_GRIDSQUARE:6>XXXXXX<MY_CITY:10>Dort<EOR>[/code]

Die Datei hat zudem am Anfang jeweils einen Header, auch im Textformat:
[codebox=text file=Unbenannt.txt]File: logbook.adi
<ADIF_VER:5>2.2.7
<PROGRAMID:6>fldigi
<PROGRAMVERSION:5>4.0.5
<EOH>[/code]

Hat jemand die Zeit und die Geduld, mich bei meinem Vorhaben zu unterstützen? Ich verspreche, ich gebe mir Mühe, nicht zu ungeduldig zu sein...
Mit ein bisschen Glück lerne ich ja dabei etwas, das ich dann in späteren Projekten wieder brauchen kann. Bitte nicht nur Ratschläge, dass ich doch zuerst einen Kurs besuchen oder ein 1000seitiges Buch lesen soll - ich lerne am besten aus Beispielen...:)

Ich freue mich auf eure Kontakte aus dem Forum.

Gruss
Marius

PS: Um allfälligen Rückfragen vorzubeugen: diese Struktur der adif-Datei ist gegeben, sie wird auch benötigt im Datenaustausch mit Drittsystemen und eben, in dieser spezifischen Applikation wie anfangs erwähnt.
AttributeError: 'power74' object has no attribute 'nervenbehalten'
BlackJack

@power74: Bei Datenformaten schaue ich immer erst einmal ob es da nicht schon etwas gibt. In diesem Fall würde ich mir beispielsweise das `hamtools.adif`-Modul von den Python Ham Radio Tools anschauen, ob das alles kann was benötigt wird.
Benutzeravatar
power74
User
Beiträge: 14
Registriert: Donnerstag 3. September 2015, 12:25
Wohnort: in der Nähe von Zürich

@BlackJack: Danke, ich könnte mir vorstellen, dass man damit etwas machen kann. Wo soll diese Datei abgelegt werden, gehört die ins Startverzeichnis von Python? (das wäre auf diesem Rechner C:\Python34)
So wie ich das verstehe, ist das ein Modul, also ein Programmteil, das noch korrekt aufgerufen werden muss, damit ich damit eine Datei bearbeiten kann?

Gruss
Marius
AttributeError: 'power74' object has no attribute 'nervenbehalten'
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das stimmt, aber du kopierst das nicht selbst irgendwo hin.

Sondern du benutzt pip, das install-tool von Python. Da sollte in einer Shell deiner Wahl

`c:\voller\pfad\zu\pip install hamtools`

reichen. Das installiert naemlich dann auch gleich noch die diversen Abhaengigkeiten mit, die das Paket braucht.
BlackJack

Wobei es das anscheinend nicht für Python 3 gibt. Müsste man also portieren oder sich weiter umschauen. Oder Python 2.7 nehmen.
Benutzeravatar
power74
User
Beiträge: 14
Registriert: Donnerstag 3. September 2015, 12:25
Wohnort: in der Nähe von Zürich

@__deets__: OK, danke, das notiere ich mir gleich, das mit dem pip...
@BlackJack: Schade, eigentlich wollte ich gar nicht mehr Python 2.x sondern direkt Python 3.x nehmen. Das wird einem an vielen Stellen im Netz empfohlen. Somit suche ich mal ein bisschen weiter, denn das mit dem Umformen von 2.x zu 3.x ist definitiv zu hoch für einen wie mich :). Zudem kann ich nicht abschätzen, ob ich mir mit einem Mischmasch dann irgendwo Fehler einhandle, die mich völlig überfordern. Demnach wähle ich weitersuchen oder abwarten, ob sich im Forum jemand meldet, der noch weitere Ideen hat zum Thema.
AttributeError: 'power74' object has no attribute 'nervenbehalten'
nezzcarth
User
Beiträge: 1634
Registriert: Samstag 16. April 2011, 12:47

Eine Rückfrage:
Ich kenne mich da nicht aus, aber der Wikipedia-Artikel klingt so, als gäbe es auch eine XML-Serialisierung des Formats (".adx"). Ist das komplett äquivalent und kann deine Software solche austauschbar mit adi Dateien verwenden, oder muss es wirklich das gezeigte Format sein? Wenn du kein Python3-Modul für adi-Dateien findest, wäre das halt eine Option, da für XML gute Module zur Verarbeitung bereitstehen; XML ist nicht das bequemste Format, aber zumindest für den Einstieg dürfte das einfacher sein, als selbst einen Parser zu basteln. In der Regel abstrahiert und trennt man solche Einlese- und Schreibprozesse ohnehin soweit von der eigentlichen Programmlogik, dass das Format später auch austauschbar wäre.
power74 hat geschrieben: Bitte nicht nur Ratschläge, dass ich doch zuerst einen Kurs besuchen oder ein 1000seitiges Buch lesen soll - ich lerne am besten aus Beispielen...:)
Ich fürchte, wenn du noch gar keine Programmiererfahrung hast, wird es allein mit Beispielen, die sich eng an deinem Anwendungsfall orientieren nicht gehen. Zumindest das Tutorial aus der Python-Doku durchzuarbeiten wäre sinnvoll. Und dabei lernt man auch anhand von Beispielen. Python hat eine interaktive Shell und m.M.n. ist einer der besseren Methoden, Python zu lernen, Beispiele dort Stück für Stück nach zu tippen und dann mit diesen ein bisschen zu spielen, also zu schauen, was passiert, wenn man was ändert usw.
Benutzeravatar
power74
User
Beiträge: 14
Registriert: Donnerstag 3. September 2015, 12:25
Wohnort: in der Nähe von Zürich

@nezzcarth: ob das Format in einer *adx Datei auch geht, muss ich bei nächster Gelegenheit prüfen, danke für den Hinweis. Ich befürchte allerdings, dass das am Ende nicht das sein wird, was ich benötige, da die diversen Online-Datenbanken (eqsl.cc, qrz.com etc.) i.d.R. "nur" dieses adif Format akzeptieren. Ich denke, dass dort dann die Schwierigkeiten beginnen, wo der gemeinsame Nenner all dieser Seiten und Programme sein wird.

Mit Deiner Antwort zum Tutorial spüre ich nun auch je länger ich da dran bin, dass Du ziemlich sicher richtig liegst :?
Ich habe mal mit einem Tutorial begonnen, das mich vom Aufbau und der Sprache angesprochen hat:
https://py-tutorial-de.readthedocs.io/de/python-3.3

Vielleicht erhalte ich nun auch Reaktionen aus dem Forum zum Thema, welche Tutorials mir helfen könnten...möchte aber nicht OT werden damit.
Also erhrlich gesagt, habe ich nicht gar keine Erfahrung in der Programmierung. Das wäre ziemlich sicher sogar besser, wenn ich gar keinen Schimmer hätte aber meine Hauptbürde ist, dass ich aus der DOS/Basic Zeit noch ein paar Programmiererinnerungen habe und das ist verd***t schwierig für mich, von dem Script/Batch-Denken wegzukommen und objektorientiert zu denken...vielleicht versteht mich da der eine oder andere, was ich meine.

Die Ferienzeit naht und mit ein bisschen Glück finde ich Zeit mich im Thema zu vertiefen.
Vermutlich helfen mir im Moment Tipps zu Tutorials für "Umdenker" von MS-Basic zu Python am meisten :)
AttributeError: 'power74' object has no attribute 'nervenbehalten'
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Und Du möchtest das wie zum Bearbeiten angezeigt bekommen?
Ich meine jetzt mit FREQ, MODE, NAME am Zeilenanfang denke ich mir, sonst würde es ja unübersichtlich. Und genügt es nicht, wenn Du die Zeilen nur vor jedem < mit \n umbrichst, damit die lesbar aufgelistet werden und nicht als Endlosstring?

[codebox=text file=Unbenannt.txt]<FREQ:8>7.041271
<CALL:6>AB1CDE
<MODE:5>PSK63
<NAME:5>XXXXX
<QSO_DATE:8>20170709
<QSO_DATE_OFF:8>20170709
<TIME_OFF:6>212515
<TIME_ON:6>212200
<QTH:5>Hieroderda
<EQSLSDATE:8>20170711
<GRIDSQUARE:6>JN00AB
<BAND:3>40m
<STATION_CALLSIGN:8>AB2FGH
<MY_GRIDSQUARE:6>XXXXXX
<MY_CITY:10>Dort
<EOR>[/code]
Und 0V1 sind ausgestorben oder kann man damit auch noch etwas empfangen?
BlackJack

@Melewo: Ich vermute mal das genügt nicht, wenn nämlich ein Feld in den Daten '>'-Zeichen enthält, und ich glaube Kommentare gibt es auch noch noch bei dem Format, die man eventuell berücksichtigen muss.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Na ich weiß nicht, ganz so kompliziert sah das bei diesem Beispiel nicht aus:

http://adif.org/305/ADIF_305.htm#ADI_Ap ... ned_Fields
BlackJack

@Melewo: Ein < kann auch *in* Werten vorkommen, und da würdest Du dann den Wert kaputt machen wenn Du einen Zeilenumbruch davor einfügst. Eine Notiz 'C++ < Python':
[codebox=text file=Unbenannt.tex]<notes:12>C++ < Python<eor>[/code]

würde dann das hier werden:
[codebox=text file=Unbenannt.tex]<notes:12>C++
< Python
<eor>[/code]
Also entweder 'C++ \n< Pytho' oder 'C++ \r\n< Pyth', je nach dem welche Bytes man da als Zeilenumbruch einfügt.

Und wenn jemand (ein Programm) die Datei von ”Kommentaren” bereinigt, dann verschwinden da 'o' oder das 'on' auch tatsächlich aus der Datei, denn die gehören ja nicht mehr zu dem Wert.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

@BlackJack: Also, wenn man die Datei parsen möchte, müssten alle möglicherweise vorkommenden <Namen: > bekannt sein und zusätzlich müsste zur Sicherheit die Anzahl der Zeichen geprüft werden, in Deinem Beispiel :12 und die Anzahl sollte ja eigentlich stimmen.
In der Schulzeit, lang ist es her, hatte ich ein paar QSL-Karten angefordert, die anzugebenen Daten hielten sich in Grenzen und mehr als ein paar Notizen waren das nicht.
BlackJack

@Melewo: Die möglicherweise vorkommenden Tags müssen nicht bekannt sein, sie können sogar nicht alle bekannt sein, weil das Format explizit auf Erweiterbarkeit ausgelegt ist. Und auch kein Textformat ist, denn der Wert zu einem Tag können auch beliebige Binärdaten sein. Die Dokumentation erwähnt als Beispiel Bilddaten. Die Längenangabe kann man nicht prüfen, beziehungsweise nur bei bekannten Tags mit einem Wert der eine bekannte Länge hat. Ansonsten *muss* die Längenangabe stimmen. Daran orientiert sich ein Parser. Wenn die nicht stimmt hat man schon verloren. Denn zwischen den Feldern darf beliebiger ”Müll”/”Kommentar” stehen, solange darin kein '<' vorkommt.

Die 12 in meinem Beispiel stimmt nur solange man den Wert nicht durch einfügen eines Zeilenumbruchs verändert. Wobei dann der Wert nicht mehr wirklich stimmt, selbst wenn man die Längenangabe auf 13 oder 14 korrigiert, je nach dem welches Byte oder welche Bytes man für den Umbruch einfügt. Die beiden Beispiele sind nicht gleich! Das erste enthält eine Notiz gefolgt vom Endkennzeichen für den Datensatz. Das zweite enthält eine Notiz, gefolgt von einem 'n' oder einem 'on', das *nicht mehr Teil der Notiz ist*, sondern ein Kommentar zwischen der Notiz und dem Endkennzeichen für den Datensatz.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Melewo: Der von Dir gepostete Link beschreibt doch sehr gut, wie das Format zu interpretieren ist. Wenngleich das Format auch fragil in Bezug auf möglich Fülldaten zwischen den Data-Specifiers eines Records ist. Die Autoren haben dabei wohl hauptsächlich an Zeilenumbrüche zur besseren Lesbarkeit gedacht, andere Zeichen aber nicht explizit ausgeschlossen. Das sollte aber nicht das Problem des Parsers sein, wenn die Daten bewusst oder aus Unachtsamkeit des Erstellers nicht korrekt interpretiert werden können. Das Format verlangt eben Sorgfalt sowohl vom Leser als auch vom Ersteller.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Bei allen Screenshots von Logbüchern habe ich bisher zumindest noch nichts gesehen, was sich nicht einfach in eine Datenbank einlesen lassen würde und Converter für CSV gibt es auch. Das Format lässt sich ja erhalten, somit nicht wirklich ein Problem.

http://www.dxshell.com/adif-master.html
BlackJack

@Melewo: Jain. Ich habe immer noch das Gefühl Du verschliesst die Augen vor der Erweiterbarkeit des Formats und ignorierst einfach alles was Du noch nicht irgendwo gesehen hast. Ein Werkzeug sollte halt nicht nur mit den Beispielen die Du gesehen hast zurecht kommen, sondern mit dem Format an sich. Genau dafür gibt es ja Spezifikationen, damit man sich nicht an einer handvoll Beispielen orientieren muss und dann jeder das etwas anders interpretiert oder Teile zu denen er noch kein Beispiel gesehen hat einfach ignoriert.

Solche Dateien in eine Datenbank einzulesen kann je nach Datenbank und was man konkret machen möchte tatsächlich *sehr* einfach sein, wenn man Beispielsweise eine dokumentorientierte DB verwendet und das Log einfach komplett als Dokuments/BLOB darin speichert, oder immer noch einfach wenn man Die Datensätze aus dem Log jeweils in einen BLOB speichert, aber auch durchaus etwas aufwändiger wenn man das Log und die Datensätze zwar aufbricht und speichert, aber eben auch *alles* speichern möchte, so das man aus den Daten in der DB auch die ursprüngliche Datei wieder rekonstruieren kann.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Ich möchte mich deshalb nicht streiten, weil es sinnlos wäre, bevor power74 nicht ausführliche Dateien preisgibt, was darin alles enthalten sein könnte. Doch hier ist mal ein simpler PHP ADIF_Parser.

https://github.com/magicbug/phpadifpars ... parser.php
BlackJack

@Melewo: Der ist *zu* simpel. Die Tags sind „case insensitiv“ und sowohl '<eoh>' als auch '<eor>' können in den Nutzdaten vorkommen. Ausserdem ist's PHP und nicht Python. :-) Ein ADIF-Parser in Python ist im `hamtools`-Package enthalten. Und der kommt mit den beiden genannten Fällen klar.

Edit: Und es ist egal was in den Dateien enthalten ist: Ein Parser sollte sich an die Spezifikation halten und nicht an Beispieldaten orientieren. Zumal die Spezifikation/das Format ja wirklich relativ einfach ist. Da ist ja nicht einmal etwas rekursives in der Grammatik — ein Lexer reicht schon aus.
nezzcarth
User
Beiträge: 1634
Registriert: Samstag 16. April 2011, 12:47

BlackJack hat geschrieben:Wobei es das anscheinend nicht für Python 3 gibt. Müsste man also portieren oder sich weiter umschauen. Oder Python 2.7 nehmen.
Ich habe unter Python3 keine Probleme damit. Allerdings ist die Beispiel-Datei defekt. An zwei Stellen die Feldlängen zu lang (vermutlich durch das Anonymisieren), was den Parser durcheinander bringt. Leider ist der Code nicht so robust, dass das erkannt word, oder zumindest irgendeinen Fehler gibt; stattdessen gibt's beim Iterieren einfach nur eine leere Liste. Wenn man die Feldlängen anpasst, kommt allerdings folgendes raus:

Code: Alles auswählen

Python 3.6.1 (default, Mar 27 2017, 00:27:06) 
[...]
In [1]: import adif
In [2]: f = open('logbook.adi', 'r')
In [3]: reader = adif.Reader(f)
In [4]: reader.adif_ver
Out[4]: '2.2.7'
In [5]: reader.header_present
Out[5]: True
In [6]: [field for field in reader]
Out[6]: 
[OrderedDict([('freq', '7.041271'),
              ('call', 'AB1CDE'),
              ('mode', 'PSK63'),
              ('name', 'XXXXX'),
              ('qso_date', '20170709'),
              ('qso_date_off', '20170709'),
              ('time_off', '212515'),
              ('time_on', '212200'),
              ('qth', 'Hiero'),
              ('eqslsdate', '20170711'),
              ('gridsquare', 'JN00AB'),
              ('band', '40m'),
              ('station_callsign', 'AB2FGH'),
              ('my_gridsquare', 'XXXXXX'),
              ('my_city', 'Dort'),
              ('app_datetime_on', datetime.datetime(2017, 7, 9, 21, 22)),
              ('app_datetime_off', datetime.datetime(2017, 7, 9, 21, 25))])]
Antworten