# callsign-regex
Python code to build a current regex to match all (legal) ham radio callsigns globally.
Based on the ITU Table of International Call Sign Series (Appendix 42 to the RR).
## Install
```bash
$ pip install callsign-regex
...
$
```
## Package stats
[![Downloads](https://static.pepy.tech/badge/callsign-regex)](https://pepy.tech/project/callsign-regex)
[![Downloads](https://static.pepy.tech/badge/callsign-regex/month)](https://pepy.tech/project/callsign-regex)
[![Downloads](https://static.pepy.tech/badge/callsign-regex/week)](https://pepy.tech/project/callsign-regex)
[![Downloads](https://static.pepy.tech/badge/callsign-regex/week)](https://pepy.tech/project/callsign-regex)
[![Downloads](https://img.shields.io/pypi/pyversions/callsign-regex.svg)](https://pepy.tech/project/callsign-regex)
## Producing a regex
Use the `-R` command line argument. The resulting output is the regex to match all ham radio callsigns: This regex string can be used in many programming languages (including Python).
```bash
$ callsign-regex -R
((2[A-Z]{1,2}|[BFGIKMNRW][A-Z]{0,2}|3[A-CE-Z][A-Z]{0,1}|4[A-MO-Z][A-Z]{0,1}|[5-9OUX][A-Z][A-Z]{0,1})([0-9][0-9A-Z]{0,3}[A-Z])|([ACDLP][2-9A-Z][A-Z]{0,1}|E[2-7A-Z][A-Z]{0,1}|H[2-46-9A-Z][A-Z]{0,1}|[JTV][2-8A-Z][A-Z]{0,1}|S[2-35-9A-RT-Z][A-Z]{0,1}|Y[2-9A-Y][A-Z]{0,1}|Z[238A-Z][A-Z]{0,1})([0-9A-Z]{0,3}[A-Z]))
$
```
If you expand the regex string to make it human readable, you'll see some of the optimized matching. Note that most regex libaries will optimize this much further when compiled.
```
(
(
2 [A-Z]{1,2} |
[BFGIKMNRW] [A-Z]{0,2} |
3[A-CE-Z] [A-Z]{0,1} |
4[A-MO-Z] [A-Z]{0,1} |
[5-9OUX][A-Z] [A-Z]{0,1}
)
(
[0-9][0-9A-Z]{0,3}[A-Z]
)
|
(
[ACDLP] [2-9A-Z][A-Z]{0,1} |
E[2-7A-Z] [A-Z]{0,1} |
H[2-46-9A-Z] [A-Z]{0,1} |
[JTV][2-8A-Z] [A-Z]{0,1} |
S[2-35-9A-RT-Z] [A-Z]{0,1} |
Y[2-9A-Y] [A-Z]{0,1} |
Z[238A-Z] [A-Z]{0,1}
)
(
[0-9A-Z]{0,3}[A-Z]
)
)
```
## Usage
```bash
$ callsign-regex --help
callsign-regex [-h] [-V] [-v] [-F] [-R] [-f] [-r]
Produce a valid optimized regex from the ITU Table of International Call Sign Series (Appendix 42 to the RR). Based on https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/glad.aspx
options:
-h, --help show this help message and exit
-V, --version dump version number
-v, --verbose verbose output
-F, --force force rebuild of cached regex
-R, --regex dump regex (to be used in code)
-f, --forward dump table (showing callsign to country table)
-r, --reverse dump reverse table (showing country to callsign table)
$
```
## Producing tables
To show the mapping of callsign to country:
```bash
$ callsign-regex -d
2 : GB/United Kingdom of Great Britain and Northern Ireland (the)
3A : MC/Monaco
3B : MU/Mauritius
3C : GQ/Equatorial Guinea
3D[A-M] : SZ/Eswatini
3D[N-Z] : FJ/Fiji
...
$
```
To show the mapping of country to callsign:
```bash
$ callsign-regex -r
AD/Andorra : C3
AE/United Arab Emirates (the) : A6
AF/Afghanistan : T6,YA
AG/Antigua and Barbuda : V2
AL/Albania : ZA
AM/Armenia : EK
...
$
```
The same output can be produced in code:
```python
from itu_appendix42 import ItuAppendix42
ituappendix42 = ItuAppendix42()
print(ItuAppendix42.regex())
```
The resulting regex can be used via many languages to pattern match a ham radio callsign correctly.
## Example code (in Python)
```python
import sys
from itu_appendix42 import ItuAppendix42
ituappendix42 = ItuAppendix42()
for line in sys.stdin:
line = line.rstrip()
v = ituappendix42.fullmatch(line)
if v:
print('%-10s' % (line))
else:
print('%-10s INVALID' % (line))
```
The file `examples/python_example.py` is on github (and is based on this code).
## Example code (in C)
```c
char *callsign_regex;
regex_t re;
regmatch_t rm[1];
callsign_regex = "<<INSERT FROM ABOVE OR READ IN FROM FILE>>";
if (regcomp(&re, callsign_regex, REG_EXTENDED) != 0) {
// bail!
}
char line[1024+1];
while ((fgets(line, 1024, stdin)) != NULL) {
if (regexec(&re, line, N_RM, rm, 0) != 0) {
// bail!
}
```
The file `examples/clang-example.c` is on github and contains fully working code with full error checking ability.
## Notes on ITU callsign Appendix 42
According to the [ITU](https://en.wikipedia.org/wiki/ITU_prefix) Wikipedia page, the following is a key issue when building a regex.
> With regard to the second and/or third letters in the prefixes in the list below,
> if the country in question is allocated all callsigns with A to Z in that position,
> then that country can also use call signs with the digits 0 to 9 in that position.
> For example, the United States is assigned KA–KZ, and therefore can also use prefixes like K1 or K9.
To clarify, the US is allocated the series `KAA - KAZ` `KBA - KBZ` ... `KZA - KZZ` and in that situation the normal regex would be `K[A-Z][A-Z]`; however, this text above allows `K[A-Z]{0-2}`.
This means that when parsing the ITU information you can drop the trailing letters from the search in this situation.
So far, I've not found this exact description of this rule within an ITU document; however, it's obvious that it is correct.
## Fetch new data files from the ITU (to freshen the version kept in the code)
The official database is kept by the ITU. It is called the Table of International Call Sign Series (Appendix 42 to the RR).
Hence, based on the page
[https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/glad.aspx](https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/glad.aspx)
visit this specific page in a browser on your system
[https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/call_sign_series.aspx](https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/call_sign_series.aspx)
and download via the somewhat small `.xlsx` button. This produces a file like this in your Download directory/folder:
```
CallSignSeriesRanges-959674f2-22a8-4eb5-aa67-9df4fd606158.xlsx
```
Your downloaded filename will be different (a different set of numbers - but the same filename format - that's fine.
This package looks for the newest file of that name pattern in your `Downloads` directory/folder, so don't worry if you have more than one file downloaded there.
Under windows the download is placed at `C:\Users\YourUsername\Downloads\` and under Linux or MacOS it's in `~/Downloads`.
A quick run of the program will read in the downloaded file and update the caches values for the regex.
Raw data
{
"_id": null,
"home_page": "https://github.com/mahtin/callsign-regex",
"name": "callsign-regex",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "Ham Radio, Callsign, ITU, Appendix42",
"author": "Martin J Levy",
"author_email": "mahtin@mahtin.com",
"download_url": "https://files.pythonhosted.org/packages/c0/cf/ee9b6815da29f21fcab7dfc5bf26ea1e151c94c40b12ae9e6042a4869f82/callsign_regex-0.7.1.tar.gz",
"platform": null,
"description": "# callsign-regex\nPython code to build a current regex to match all (legal) ham radio callsigns globally.\nBased on the ITU Table of International Call Sign Series (Appendix 42 to the RR).\n\n## Install\n\n```bash\n$ pip install callsign-regex\n...\n$\n```\n\n## Package stats\n\n[![Downloads](https://static.pepy.tech/badge/callsign-regex)](https://pepy.tech/project/callsign-regex)\n[![Downloads](https://static.pepy.tech/badge/callsign-regex/month)](https://pepy.tech/project/callsign-regex)\n[![Downloads](https://static.pepy.tech/badge/callsign-regex/week)](https://pepy.tech/project/callsign-regex)\n[![Downloads](https://static.pepy.tech/badge/callsign-regex/week)](https://pepy.tech/project/callsign-regex)\n[![Downloads](https://img.shields.io/pypi/pyversions/callsign-regex.svg)](https://pepy.tech/project/callsign-regex)\n\n## Producing a regex\n\nUse the `-R` command line argument. The resulting output is the regex to match all ham radio callsigns: This regex string can be used in many programming languages (including Python).\n\n```bash\n$ callsign-regex -R\n((2[A-Z]{1,2}|[BFGIKMNRW][A-Z]{0,2}|3[A-CE-Z][A-Z]{0,1}|4[A-MO-Z][A-Z]{0,1}|[5-9OUX][A-Z][A-Z]{0,1})([0-9][0-9A-Z]{0,3}[A-Z])|([ACDLP][2-9A-Z][A-Z]{0,1}|E[2-7A-Z][A-Z]{0,1}|H[2-46-9A-Z][A-Z]{0,1}|[JTV][2-8A-Z][A-Z]{0,1}|S[2-35-9A-RT-Z][A-Z]{0,1}|Y[2-9A-Y][A-Z]{0,1}|Z[238A-Z][A-Z]{0,1})([0-9A-Z]{0,3}[A-Z]))\n$\n```\n\nIf you expand the regex string to make it human readable, you'll see some of the optimized matching. Note that most regex libaries will optimize this much further when compiled.\n\n```\n (\n (\n 2 [A-Z]{1,2} |\n [BFGIKMNRW] [A-Z]{0,2} |\n 3[A-CE-Z] [A-Z]{0,1} |\n 4[A-MO-Z] [A-Z]{0,1} |\n [5-9OUX][A-Z] [A-Z]{0,1}\n )\n (\n [0-9][0-9A-Z]{0,3}[A-Z]\n )\n |\n (\n [ACDLP] [2-9A-Z][A-Z]{0,1} |\n E[2-7A-Z] [A-Z]{0,1} |\n H[2-46-9A-Z] [A-Z]{0,1} |\n [JTV][2-8A-Z] [A-Z]{0,1} |\n S[2-35-9A-RT-Z] [A-Z]{0,1} |\n Y[2-9A-Y] [A-Z]{0,1} |\n Z[238A-Z] [A-Z]{0,1}\n )\n (\n [0-9A-Z]{0,3}[A-Z]\n )\n )\n```\n\n## Usage\n\n```bash\n$ callsign-regex --help\ncallsign-regex [-h] [-V] [-v] [-F] [-R] [-f] [-r]\n\nProduce a valid optimized regex from the ITU Table of International Call Sign Series (Appendix 42 to the RR). Based on https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/glad.aspx\n\noptions:\n -h, --help show this help message and exit\n -V, --version dump version number\n -v, --verbose verbose output\n -F, --force force rebuild of cached regex\n -R, --regex dump regex (to be used in code)\n -f, --forward dump table (showing callsign to country table)\n -r, --reverse dump reverse table (showing country to callsign table)\n$\n```\n\n## Producing tables\n\nTo show the mapping of callsign to country:\n\n```bash\n$ callsign-regex -d\n2 : GB/United Kingdom of Great Britain and Northern Ireland (the)\n3A : MC/Monaco\n3B : MU/Mauritius\n3C : GQ/Equatorial Guinea\n3D[A-M] : SZ/Eswatini\n3D[N-Z] : FJ/Fiji\n...\n$\n\n```\n\nTo show the mapping of country to callsign:\n\n```bash\n$ callsign-regex -r\nAD/Andorra : C3\nAE/United Arab Emirates (the) : A6\nAF/Afghanistan : T6,YA\nAG/Antigua and Barbuda : V2\nAL/Albania : ZA\nAM/Armenia : EK\n...\n$\n```\n\nThe same output can be produced in code:\n```python\nfrom itu_appendix42 import ItuAppendix42\n\nituappendix42 = ItuAppendix42()\nprint(ItuAppendix42.regex())\n```\n\nThe resulting regex can be used via many languages to pattern match a ham radio callsign correctly.\n\n## Example code (in Python)\n\n```python\nimport sys\nfrom itu_appendix42 import ItuAppendix42\n\nituappendix42 = ItuAppendix42()\n\nfor line in sys.stdin:\n line = line.rstrip()\n v = ituappendix42.fullmatch(line)\n if v:\n print('%-10s' % (line))\n else:\n print('%-10s INVALID' % (line))\n```\n\nThe file `examples/python_example.py` is on github (and is based on this code).\n\n## Example code (in C)\n\n```c\n char *callsign_regex;\n regex_t re;\n regmatch_t rm[1];\n\n callsign_regex = \"<<INSERT FROM ABOVE OR READ IN FROM FILE>>\";\n\n if (regcomp(&re, callsign_regex, REG_EXTENDED) != 0) {\n // bail!\n }\n\n char line[1024+1];\n while ((fgets(line, 1024, stdin)) != NULL) {\n if (regexec(&re, line, N_RM, rm, 0) != 0) {\n // bail!\n }\n```\n\nThe file `examples/clang-example.c` is on github and contains fully working code with full error checking ability.\n\n## Notes on ITU callsign Appendix 42\n\nAccording to the [ITU](https://en.wikipedia.org/wiki/ITU_prefix) Wikipedia page, the following is a key issue when building a regex.\n\n> With regard to the second and/or third letters in the prefixes in the list below,\n> if the country in question is allocated all callsigns with A to Z in that position,\n> then that country can also use call signs with the digits 0 to 9 in that position.\n> For example, the United States is assigned KA\u2013KZ, and therefore can also use prefixes like K1 or K9.\n\nTo clarify, the US is allocated the series `KAA - KAZ` `KBA - KBZ` ... `KZA - KZZ` and in that situation the normal regex would be `K[A-Z][A-Z]`; however, this text above allows `K[A-Z]{0-2}`.\n\nThis means that when parsing the ITU information you can drop the trailing letters from the search in this situation.\nSo far, I've not found this exact description of this rule within an ITU document; however, it's obvious that it is correct.\n\n## Fetch new data files from the ITU (to freshen the version kept in the code)\n\nThe official database is kept by the ITU. It is called the Table of International Call Sign Series (Appendix 42 to the RR).\n\nHence, based on the page\n[https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/glad.aspx](https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/glad.aspx)\nvisit this specific page in a browser on your system\n[https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/call_sign_series.aspx](https://www.itu.int/en/ITU-R/terrestrial/fmd/Pages/call_sign_series.aspx)\nand download via the somewhat small `.xlsx` button. This produces a file like this in your Download directory/folder:\n```\n CallSignSeriesRanges-959674f2-22a8-4eb5-aa67-9df4fd606158.xlsx\n```\nYour downloaded filename will be different (a different set of numbers - but the same filename format - that's fine.\n\nThis package looks for the newest file of that name pattern in your `Downloads` directory/folder, so don't worry if you have more than one file downloaded there.\nUnder windows the download is placed at `C:\\Users\\YourUsername\\Downloads\\` and under Linux or MacOS it's in `~/Downloads`.\n\nA quick run of the program will read in the downloaded file and update the caches values for the regex.\n\n",
"bugtrack_url": null,
"license": "OSI Approved :: MIT License",
"summary": "Match ham radio callsigns based on ITU appendix42",
"version": "0.7.1",
"project_urls": {
"Download": "https://github.com/mahtin/callsign-regex/archive/refs/tags/0.7.1.tar.gz",
"Homepage": "https://github.com/mahtin/callsign-regex"
},
"split_keywords": [
"ham radio",
" callsign",
" itu",
" appendix42"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "72c735a1246f4d82caac7db3c4228e72fe39854702ba1f240c62443f4476e0fe",
"md5": "67a74a82da21f37bd879df4c0e29f207",
"sha256": "38d23d58b223519c238842d8ccddb8e57bac079f9b9ff194c388ba40714a7c49"
},
"downloads": -1,
"filename": "callsign_regex-0.7.1-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "67a74a82da21f37bd879df4c0e29f207",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": ">=3.7",
"size": 37802,
"upload_time": "2024-12-20T16:40:50",
"upload_time_iso_8601": "2024-12-20T16:40:50.275553Z",
"url": "https://files.pythonhosted.org/packages/72/c7/35a1246f4d82caac7db3c4228e72fe39854702ba1f240c62443f4476e0fe/callsign_regex-0.7.1-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "c0cfee9b6815da29f21fcab7dfc5bf26ea1e151c94c40b12ae9e6042a4869f82",
"md5": "3bebfab8487204c392451cbe425403e2",
"sha256": "032de88e2267f47be2eebb8443446f7fed57eb4023e84b5c0fb2ae12dd5b0a32"
},
"downloads": -1,
"filename": "callsign_regex-0.7.1.tar.gz",
"has_sig": false,
"md5_digest": "3bebfab8487204c392451cbe425403e2",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 36881,
"upload_time": "2024-12-20T16:40:52",
"upload_time_iso_8601": "2024-12-20T16:40:52.810959Z",
"url": "https://files.pythonhosted.org/packages/c0/cf/ee9b6815da29f21fcab7dfc5bf26ea1e151c94c40b12ae9e6042a4869f82/callsign_regex-0.7.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-20 16:40:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mahtin",
"github_project": "callsign-regex",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "openpyxl",
"specs": []
}
],
"lcname": "callsign-regex"
}