Pavel D inherited some… we’ll call it “software”… that helps run warehouse operations for a boiler/heating manufacturer. That software was a Visual FoxPro database.

Now, this application needs to read barcodes off of products in the warehouse. Since the laser-scanners can sometimes mis-read those barcodes, the database uses a custom check-sum algorithm.

FUNCTION GetCheckSum
   LPARAMETERS lcSerNum
   LOCAL lnCalcSum, lnI, lcCheckSum
   m.lnCalcSum=0
   FOR lnI=1 TO LEN( m.lcSerNum )
      DO CASE
      CASE SUBSTR(m.lcSerNum, m.lnI,1)= ' '
         m.lnCalcSum= m.lnCalcSum+0*m.lnI
      CASE SUBSTR(m.lcSerNum, m.lnI,1)= '!'
         m.lnCalcSum= m.lnCalcSum+1*m.lnI
      CASE SUBSTR(m.lcSerNum, m.lnI,1)= '"'
         m.lnCalcSum= m.lnCalcSum+2*m.lnI
      CASE SUBSTR(m.lcSerNum, m.lnI,1)= '#'
         m.lnCalcSum= m.lnCalcSum+3*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='$'
         m.lnCalcSum=m.lnCalcSum+4*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='%'
         m.lnCalcSum=m.lnCalcSum+5*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='&'
         m.lnCalcSum=m.lnCalcSum+6*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)="'"
         m.lnCalcSum=m.lnCalcSum+7*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='('
         m.lnCalcSum=m.lnCalcSum+8*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)=')'
         m.lnCalcSum=m.lnCalcSum+9*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='*'
         m.lnCalcSum=m.lnCalcSum+10*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='+'
         m.lnCalcSum=m.lnCalcSum+11*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)=','
         m.lnCalcSum=m.lnCalcSum+12*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='-'
         m.lnCalcSum=m.lnCalcSum+13*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='.'
         m.lnCalcSum=m.lnCalcSum+14*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='/'
         m.lnCalcSum=m.lnCalcSum+15*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='0'
         m.lnCalcSum=m.lnCalcSum+16*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='1'
         m.lnCalcSum=m.lnCalcSum+17*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='2'
         m.lnCalcSum=m.lnCalcSum+18*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='3'
         m.lnCalcSum=m.lnCalcSum+19*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='4'
         m.lnCalcSum=m.lnCalcSum+20*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='5'
         m.lnCalcSum=m.lnCalcSum+21*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='6'
         m.lnCalcSum=m.lnCalcSum+22*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='7'
         m.lnCalcSum=m.lnCalcSum+23*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='8'
         m.lnCalcSum=m.lnCalcSum+24*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='9'
         m.lnCalcSum=m.lnCalcSum+25*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)=':'
         m.lnCalcSum=m.lnCalcSum+26*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)=';'
         m.lnCalcSum=m.lnCalcSum+27*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='<'
         m.lnCalcSum=m.lnCalcSum+28*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='='
         m.lnCalcSum=m.lnCalcSum+29*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='>'
         m.lnCalcSum=m.lnCalcSum+30*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='?'
         m.lnCalcSum=m.lnCalcSum+31*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='@'
         m.lnCalcSum=m.lnCalcSum+32*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='A'
         m.lnCalcSum=m.lnCalcSum+33*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='B'
         m.lnCalcSum=m.lnCalcSum+34*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='C'
         m.lnCalcSum=m.lnCalcSum+35*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='D'
         m.lnCalcSum=m.lnCalcSum+36*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='E'
         m.lnCalcSum=m.lnCalcSum+37*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='F'
         m.lnCalcSum=m.lnCalcSum+38*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='G'
         m.lnCalcSum=m.lnCalcSum+39*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='H'
         m.lnCalcSum=m.lnCalcSum+40*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='I'
         m.lnCalcSum=m.lnCalcSum+41*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='J'
         m.lnCalcSum=m.lnCalcSum+42*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='K'
         m.lnCalcSum=m.lnCalcSum+43*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='L'
         m.lnCalcSum=m.lnCalcSum+44*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='M'
         m.lnCalcSum=m.lnCalcSum+45*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='N'
         m.lnCalcSum=m.lnCalcSum+46*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='O'
         m.lnCalcSum=m.lnCalcSum+47*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='P'
         m.lnCalcSum=m.lnCalcSum+48*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='Q'
         m.lnCalcSum=m.lnCalcSum+49*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='R'
         m.lnCalcSum=m.lnCalcSum+50*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='S'
         m.lnCalcSum=m.lnCalcSum+51*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='T'
         m.lnCalcSum=m.lnCalcSum+52*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='U'
         m.lnCalcSum=m.lnCalcSum+53*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='V'
         m.lnCalcSum=m.lnCalcSum+54*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='W'
         m.lnCalcSum=m.lnCalcSum+55*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='X'
         m.lnCalcSum=m.lnCalcSum+56*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='Y'
         m.lnCalcSum=m.lnCalcSum+57*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='Z'
         m.lnCalcSum=m.lnCalcSum+58*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='['
         m.lnCalcSum=m.lnCalcSum+59*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='\'
         m.lnCalcSum=m.lnCalcSum+60*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)=']'
         m.lnCalcSum=m.lnCalcSum+61*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='^'
         m.lnCalcSum=m.lnCalcSum+62*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='_'
         m.lnCalcSum=m.lnCalcSum+63*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='`'
         m.lnCalcSum=m.lnCalcSum+64*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='a'
         m.lnCalcSum=m.lnCalcSum+65*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='b'
         m.lnCalcSum=m.lnCalcSum+66*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='c'
         m.lnCalcSum=m.lnCalcSum+67*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='d'
         m.lnCalcSum=m.lnCalcSum+68*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='e'
         m.lnCalcSum=m.lnCalcSum+69*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='f'
         m.lnCalcSum=m.lnCalcSum+70*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='g'
         m.lnCalcSum=m.lnCalcSum+71*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='h'
         m.lnCalcSum=m.lnCalcSum+72*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='i'
         m.lnCalcSum=m.lnCalcSum+73*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='j'
         m.lnCalcSum=m.lnCalcSum+74*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='k'
         m.lnCalcSum=m.lnCalcSum+75*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='l'
         m.lnCalcSum=m.lnCalcSum+76*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='m'
         m.lnCalcSum=m.lnCalcSum+77*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='n'
         m.lnCalcSum=m.lnCalcSum+78*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='o'
         m.lnCalcSum=m.lnCalcSum+79*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='p'
         m.lnCalcSum=m.lnCalcSum+80*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='q'
         m.lnCalcSum=m.lnCalcSum+81*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='r'
         m.lnCalcSum=m.lnCalcSum+82*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='s'
         m.lnCalcSum=m.lnCalcSum+83*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='t'
         m.lnCalcSum=m.lnCalcSum+84*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='u'
         m.lnCalcSum=m.lnCalcSum+85*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='v'
         m.lnCalcSum=m.lnCalcSum+86*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='w'
         m.lnCalcSum=m.lnCalcSum+87*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='x'
         m.lnCalcSum=m.lnCalcSum+88*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='y'
         m.lnCalcSum=m.lnCalcSum+89*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='z'
         m.lnCalcSum=m.lnCalcSum+90*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='{'
         m.lnCalcSum=m.lnCalcSum+91*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='|'
         m.lnCalcSum=m.lnCalcSum+92*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='}'
         m.lnCalcSum=m.lnCalcSum+93*m.lnI
      CASE SUBSTR(m.lcSerNum,m.lnI,1)='~'
         m.lnCalcSum=m.lnCalcSum+94*m.lnI
      ENDCASE
   ENDFOR
   m.lcCheckSum = RIGHT(STR(m.lnCalcSum,7,0),1)
   RETURN m.lcCheckSum
ENDFUNC

Now, the obvious issue here is that the entire “CASE ” statement could be replaced with a call to “ASC”, which returns the ASCII code for a given character , but as Pavel notes, “the value of a character at position which equals a multiple of 10 is ignored”.

Pavel was tasked with reimplementing this in Python, and after a little thought, recreated the function in a much more concise fashion:

def validate(sn):
    checksum = 0

    for i, x in enumerate(sn[:-1]):
        checksum += (i + 1) * (ord(x) - 32)

    return str(checksum % 10) == sn[-1]
[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!