Categories
python Technology

Postcode, Barcode and python code

I’ve had a strange thing happening a while ago. I sent a CD in a padded envelope to someone, and it was returned to me. Well, it didn’t look like it was returned, more like they actually delivered it to me instead of to the person I sent it to.

Then I noticed something. I was re-using an old envelope. For environmental reasons of course (read: being so tight-assed, saving money on padded envelopes). I did write the destination address on the right side, so my address was nowhere on the envelope. What was left there however was this tiny printed barcode used by the previous sender with my address.

So it occurred to me, the postoffice didn’t even bother reading the address I put there, it scanned the little barcode instead.

Neat. So maybe I could print those barcodes and make sure my letters get to the right destination.

A little googling brought me to this nice web page you can put your postcode and it generates a string for you, which if you use in a word processor with a special barcode font (also available for download there), you can print out yourself.

That’s nice. What I couldn’t work out however, is how the postcode checksum is calculated. The website was nice enough to do it for you, but what happens if it’s unavailable or goes down??

My good friend Dan, after noticing I used those fancy barcodes on a letter I sent him, managed to find more information about the checksum algorithm, and was even kind enough to write some perl code that runs it.

When Dan shares his code I’ll link to it, but meanwhile, and just to practice with some python coding, I wrote my own python code to do the same thing (but obviously in a much nicer way than perl):

#!/usr/bin/env python

import sys
import re

if len(sys.argv)<2:
  print """
    Usage: Postcode.py <PostCode> [<Suffix>]
    
    <PostCode> must appear with no spaces, e.g. SN34RD, case insensitive
    <Suffix> is optional and set by default to 9Z (if you don't know it, don't use it)
  """
  sys.exit()

Suffix = '9Z'
if len(sys.argv)>2:
  Suffix = sys.argv[2].upper()

if len(Suffix)!=2:
  print """
  Suffix or postcode incorrect. 
   Please use postcodes without spaces or enclosed in ""
   Suffix must be 2 characters (or blank to use 9Z) 
  """
  sys.exit()

# Check for correctness of postcode. Regular expression found at http://regexlib.com/REDetails.aspx?regexp_id=260
# (notice - not at top of the page, but on one of the bottom comments)  
if not re.match("^(([A-PR-UWYZ]{1,2}[0-9]{1,2}[ABEHJMNPRVWXY]?)\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\s?(0AA))$", sys.argv[1].upper()):
  print "Postcode incorrect. Please use correct UK postcodes and either without spaces or enclosed in \"\""
  sys.exit()
      
Postcode = sys.argv[1].upper().replace(' ','') + Suffix

# Matrix as it appears on the PDF guide. Note arrays are referenced from 0..5
PostCodeMatrix = [
                  ['0','1','2','3','4','5'], 
                  ['6','7','8','9','A','B'],
                  ['C','D','E','F','G','H'],
                  ['I','J','K','L','M','N'],
                  ['O','P','Q','R','S','T'],
                  ['U','V','W','X','Y','Z']
                 ]

# A 'reverse-lookup' dictionary for each postcode character
PostCodeDict = {}
for row in range (0,6):  
  for col in range (0,6):    
    PostCodeDict[(PostCodeMatrix[row][col])] = ((row+1)%6,(col+1)%6)

(rowSum, colSum) = (0,0)
for i in Postcode:
  rowSum += PostCodeDict[i][0]
  colSum += PostCodeDict[i][1]  

Postcode += PostCodeMatrix[(rowSum%6)-1][(colSum%6)-1]
print "(%s)" % Postcode

Leave a Reply

Your email address will not be published. Required fields are marked *