Far back in time, almost one year ago, we mentioned that “An ADIF parser for Python was hacked together based on rough regular expressions (more on that in a later blog post, probably)”. Here is the later blog post.

The ADIF format is a common format for QSO data, which exists in several versions. We’ll focus on the first versions, since this is the format in which our QSO data is archived.

Essentially, these data consist of a series of tags in the format <[property name]:[number of characters]>[value]. Properly parsing this means that all properties should be extracted independently, that we use the field length to know where to stop, parse the values into the correct datatype, blablabla. We, however, will instead cheat extensively.

Judging from a few samples of our logs, the fields of interest are mostly named the same, and obey the simple rule above. In addition, each QSO record is on a separate line, which simplifies parsing. For a given property name, like “operator”, the values are simply parsed using the following regular expression:


With this, we look for the first occurrence of <operator:[number]>, and extract all characters except for < ([^<]) until the next property tag.

Applying this regular expression on each line of the QSO log will yield us the operators associated with each QSO. Assuming that the variable pattern is set to the pattern above, this is simply done using

import re
operators = [re.match(pattern, line)[1] for line in adif_file_contents]

And that’s really it. Looping over each expected property name, like operator, qso_date, call, time_on, will yield us the operator, date, worked call and time for each QSO in the log. Applying the regular expression on each line of the file for each expected property means that we will pass through the file several times, which is not very efficient. But luckily, the title of this post was “Least effort”, not “Least waste of computational power and IO operations”. B)

ADIF parsers are not that interesting, despite the fact that we made a blog post about it. To spice up this post a bit: Here is how we can use the logs to exploit the privacy of our friends LA3WUA and LB6RH, and see what we can find out about their QSO habits.

We started logging all QSOs electronically in 2011-2012 (before then, only contests were logged using computer software, all other QSOs being logged on paper). This makes for a nice historical archive, so we wrote a function for locating all ADIF files in the containing root directory and reading and combining the QSO data to a huge Pandas dataframe. Pandas can help us handle the data in a nice way, as outlined in this previous blog post.

For example, running the following command

qsos[['year', 'operator', 'call']][(qsos.operator == 'LA3WUA ')].groupby(('year', 'operator')).count()

yields the yearly QSO statistics of LA3WUA:

year operator  
2013 LA3WUA 5
2014 LA3WUA 1408
2015 LA3WUA 530
2016 LA3WUA 654
2017 LA3WUA 578

We can detect that LA3WUA obtained his callsign in 2013, and went into full ragemode in 2014 with a total number of 1408 QSOs during that year. In a similar vein, we can see the number of QSOs made by Jens under his call signs DK2AB and LB6RH:

LB6RH lived in Trondheim in 2012/2013 and was a full-time member of ARK before he moved away, but consistently returned to visit us every September in 2013, 2014, 2015 and 2016 in order to participate in Field Day. He finally came back full-time in 2017, which his QSO frequency in LA1K’s log clearly reflects – both his full-time stays and his visits during Field Day, with a nice number of QSOs every month he has been present :D.

Around 2014, the Norwegian Communications Authority started giving out LB licenses to new ham radio operators instead of LA licenses (e.g. LB6RH instead of LA3WUA). Also this can be detected in our bulk log:

With some imagination, we can see that the LA licensees are slowly replaced by LB licensees over a duration of approximately three years. This is also the mean turnover rate of ARK members, who typically stay active-active around 3-4 years with some exceptions.

Much fun can be had. A couple of our members have been working on digitizing our old paper logs, and saving them as ADIF files. It will be interesting to look at statistics over the years once this work is done.

There also exists toolboxes for parsing ADIF files which probably will produce far more consistent, reliable and general results than the quick and dirty solution we have presented here. Examples include https://github.com/n1ywb/python-hamtools and https://github.com/ctjacobs/pyqso. The latter was used by LB6RH for analyzing the Field Day logs from 2018. For what it’s worth, the Python code presented in this blog post is available on GitHub.