Reading a Cabrillo file

All contest loggers can output their data as Cabrillo format, slight warning however... some contests (looking at the RSGB,WAE) however have a modified format... I mean, we all like standard/non-standard stuff eh ?

In case you have no clue what I am talking about this is an old Cabrillo file - when I was in Oman

START-OF-LOG: 3.0
CALLSIGN: A45WG
CONTEST: DARC-WAEDC-CW
CATEGORY: SINGLE-OP HIGH
CATEGORY-OPERATOR: SINGLE-OP
CATEGORY-BAND: ALL
CATEGORY-POWER: HIGH
CATEGORY-MODE: CW
CLAIMED-SCORE: 291226
CLUB:
LOCATION: LL93FO
CREATED-BY: RUMlogNG (2.11) by DL2RUM
EMAIL: hi@dd.en
NAME: Tim Seed
ADDRESS: A House
ADDRESS: A Road
ADDRESS: A City
ADDRESS: Sultanate of Oman
OPERATORS: A45wg
SOAPBOX: Very enjoyable - the QTCs are a great idea.
QSO: 14023 CW 2016-08-13 0340 A45WG         599 001    UW2M          599 205    0
QSO: 14045 CW 2016-08-13 0344 A45WG         599 002    IZ2GRG        599 129    0
QSO: 14045 CW 2016-08-13 0345 A45WG         599 003    HG7T          599 304    0
QSO: 14045 CW 2016-08-13 0345 A45WG         599 004    DJ5MW         599 262    0
QSO: 14045 CW 2016-08-13 0346 A45WG         599 005    UW7M          599 72     0
QSO: 14045 CW 2016-08-13 0346 A45WG         599 006    DM6V          599 328    0
QSO: 14045 CW 2016-08-13 0346 A45WG         599 007    RT4F          599 249    0
QSO: 14045 CW 2016-08-13 0347 A45WG         599 008    UW3U          599 195    0
QSO: 14045 CW 2016-08-13 0347 A45WG         599 009    RA1TU         599 010    0
QSO: 14045 CW 2016-08-13 0348 A45WG         599 010    SN7Q          599 292    0
QSO: 14045 CW 2016-08-13 0348 A45WG         599 011    9A5Y          599 316    0
QSO: 14045 CW 2016-08-13 0348 A45WG         599 012    LY9A          599 117    0
QSO: 14045 CW 2016-08-13 0349 A45WG         599 013    UT4U          599 264    0
QSO: 14045 CW 2016-08-13 0349 A45WG         599 014    ES5Q          599 278    0
QSO: 14045 CW 2016-08-13 0350 A45WG         599 015    HA6NL         599 179    0
QSO: 14045 CW 2016-08-13 0350 A45WG         599 016    RZ4AG         599 68     0
QSO: 14045 CW 2016-08-13 0351 A45WG         599 017    OH3GZ         599 1      0
QSO: 14045 CW 2016-08-13 0351 A45WG         599 018    DL5LYM        599 143    0
QSO: 14045 CW 2016-08-13 0352 A45WG         599 019    R4WAE         599 20     0
END-OF-LOG:

So .. lets's process that file. And by process - I mean read it.

Cabrillo Reading in Python

This is how to parse a CBR file

from dataclasses import dataclass
from datetime import datetime



#Open and Filter QSO Lines
with open('data.cbr',"rt") as cbrfile:
    lines=[a for a in cbrfile.read().split('\n') if a.startswith('QSO')]


@dataclass
class CabrilloRec:
    "0         1         2         3         4         5         6         7         "
    "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
    "QSO: 14006 CW 2021-07-10 1200 DX0HQ         599 PARA   8N3HQ         599 JARL  "

    """Class for keeping track of an item in inventory."""
    freq: int
    mode: str
    when: datetime 
    sender: str
    senderrst: str
    senderex: str    
    receiver: str
    receiverrst: str
    receiverex: str


from pprint import pprint
Records=[]
for line in lines:              # Uncomment if you are having data mis-alignment
  #  print(line)
  #  print(line[5:10])
  #  print(line[11:13])
  #  print(line[14:24])
  #  print(line[25:30])
  #  print(line[30:43])
  #  print(line[44:48])
  #  print(line[48:55])
  #  print(line[55:69])
  #  print(line[69:72])
  #  print(line[73:78])
    Records.append(CabrilloRec(int(line[5:10]),
                               line[11:14].strip(),
                               datetime.strptime(line[14:24]+' '+line[25:29], '%Y-%m-%d %H%M'),
                               line[30:43].strip(),
                               line[44:48].strip(),
                               line[48:55].strip(),
                               line[55:69].strip(),
                               line[69:72].strip(),
                               line[73:78].strip()))

With the File now read in as a List of CabrilloRec objects, we can now create a Pandas DataFrame.

df_orig=pd.DataFrame.from_records(Records)