Wednesday, October 15, 2008

Expanding barcode scans into EANs

I recently had a project where I had to use a barcode scanner to make scans of numbers that were possibly smaller than the 13 digit EAN standard. I had to then check these against the same number in a list, but the numbers in the list had been expanded to 13 digits using the algorithm below:

If the scanned number has 13 or more digits, return it.
If the scanned number has 12 digits, prepend a zero and return the result.

If the scanned number had 6 digits, treat it as a Zero Compressed UPC-E, expand it 11 digits using the following table and continue:

Last digit UPC-E equivalent is UPC-A equivalent is
0 XXNNN0 0XX000-00NNN + check
1 XXNNN1 0XX100-00NNN + check
2 XXNNN2 0XX200-00NNN + check
3 XXXNN3 0XXX00-000NN + check
4 XXXXN4 0XXXX0-0000N + check
5 XXXXX5 0XXXXX-00005 + check
6 XXXXX6 0XXXXX-00006 + check
7 XXXXX7 0XXXXX-00007 + check
8 XXXXX8 0XXXXX-00008 + check
9 XXXXX9 0XXXXX-00009 + check

If the number (as scanned or expanded) has less than 12 digits, left pad it to 12 digits using zeros, add a check digit, and return the result.

The check digit is computed as follows:
  1. Sum the digits in all odd positions, and multiply the result by 3.
  2. Sum the digits in all even positions.
  3. Sum the totals calculated in steps 2 and 3.
  4. The check digit is 10 - (sum_of_totals % 10)
Here is my C# program that I used to work this out:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1 {
class Program {
protected static int[][] upcPartialChecksumDigit = new int[][]{
new int[] { 0 * 1, 1 * 1, 2 * 1, 3 * 1, 4 * 1, 5 * 1, 6 * 1, 7 * 1, 8 * 1, 9 * 1 }, // 0
new int[] { 0 * 3, 1 * 3, 2 * 3, 3 * 3, 4 * 3, 5 * 3, 6 * 3, 7 * 3, 8 * 3, 9 * 3 }, // 1
new int[] { 0 * 1, 1 * 1, 2 * 1, 3 * 1, 4 * 1, 5 * 1, 6 * 1, 7 * 1, 8 * 1, 9 * 1 }, // 2
new int[] { 0 * 3, 1 * 3, 2 * 3, 3 * 3, 4 * 3, 5 * 3, 6 * 3, 7 * 3, 8 * 3, 9 * 3 }, // 3
new int[] { 0 * 1, 1 * 1, 2 * 1, 3 * 1, 4 * 1, 5 * 1, 6 * 1, 7 * 1, 8 * 1, 9 * 1 }, // 4
new int[] { 0 * 3, 1 * 3, 2 * 3, 3 * 3, 4 * 3, 5 * 3, 6 * 3, 7 * 3, 8 * 3, 9 * 3 }, // 5
new int[] { 0 * 1, 1 * 1, 2 * 1, 3 * 1, 4 * 1, 5 * 1, 6 * 1, 7 * 1, 8 * 1, 9 * 1 }, // 6
new int[] { 0 * 3, 1 * 3, 2 * 3, 3 * 3, 4 * 3, 5 * 3, 6 * 3, 7 * 3, 8 * 3, 9 * 3 }, // 7
new int[] { 0 * 1, 1 * 1, 2 * 1, 3 * 1, 4 * 1, 5 * 1, 6 * 1, 7 * 1, 8 * 1, 9 * 1 }, // 8
new int[] { 0 * 3, 1 * 3, 2 * 3, 3 * 3, 4 * 3, 5 * 3, 6 * 3, 7 * 3, 8 * 3, 9 * 3 }, // 9
new int[] { 0 * 1, 1 * 1, 2 * 1, 3 * 1, 4 * 1, 5 * 1, 6 * 1, 7 * 1, 8 * 1, 9 * 1 }, // 10
new int[] { 0 * 3, 1 * 3, 2 * 3, 3 * 3, 4 * 3, 5 * 3, 6 * 3, 7 * 3, 8 * 3, 9 * 3 } // 11
};

/*
Note 6 digit UPC-E codes are expanded to 12 digit UPC-A codesas follows:
0 XXNNN0 00XX000-00NNN + check
1 XXNNN1 00XX100-00NNN + check
2 XXNNN2 00XX200-00NNN + check
3 XXXNN3 00XXX00-000NN + check
4 XXXXN4 00XXXX0-0000N + check
5 XXXXX5 00XXXXX-00005 + check
6 XXXXX6 00XXXXX-00006 + check
7 XXXXX7 00XXXXX-00007 + check
8 XXXXX8 00XXXXX-00008 + check
9 XXXXX9 00XXXXX-00009 + check
*/
public static string getUPC(string id) {
if (id == null) return null;

StringBuilder s = new StringBuilder("0", 11);
if (id.Length == 6) {
switch (id[5] - '0') {
case 0:
id = s.Append(id[0]).Append(id[1]).Append("00000").Append(id[2]).Append(id[3]).Append(id[4]).ToString();
break;
case 1:
id = s.Append(id[0]).Append(id[1]).Append("10000").Append(id[2]).Append(id[3]).Append(id[4]).ToString();
break;
case 2:
id = s.Append(id[0]).Append(id[1]).Append("20000").Append(id[2]).Append(id[3]).Append(id[4]).ToString();
break;
case 3:
id = s.Append(id[0]).Append(id[1]).Append(id[2]).Append("00000").Append(id[3]).Append(id[4]).ToString();
break;
case 4:
id = s.Append(id[0]).Append(id[1]).Append(id[2]).Append(id[3]).Append("00000").Append(id[4]).ToString();
break;
case 5:
id = s.Append(id[0]).Append(id[1]).Append(id[2]).Append(id[3]).Append(id[4]).Append("00005").ToString();
break;
case 6:
id = s.Append(id[0]).Append(id[1]).Append(id[2]).Append(id[3]).Append(id[4]).Append("00006").ToString();
break;
case 7:
id = s.Append(id[0]).Append(id[1]).Append(id[2]).Append(id[3]).Append(id[4]).Append("00007").ToString();
break;
case 8:
id = s.Append(id[0]).Append(id[1]).Append(id[2]).Append(id[3]).Append(id[4]).Append("00008").ToString();
break;
case 9:
id = s.Append(id[0]).Append(id[1]).Append(id[2]).Append(id[3]).Append(id[4]).Append("00009").ToString();
break;
default:
return null;
}
}
if (id.Length < 12) {
id = id.PadLeft(12, '0');
int checksum = 0;
for (int i = 0; i < 12; i++) { //should get unrolled by compiler hopefully
int c = id[i] - '0';
if (c < 0 || c > 9) return null;
int partial = upcPartialChecksumDigit[i][c];
checksum += partial;
}
char checksumDigit = (char)((10 - (checksum % 10)) + '0');
id += checksumDigit;
}
else if (id.Length == 12) {
id = '0' + id;
}
return id;
}



static void Main(string[] args) {
string s = ConvertUPC("654321");
Console.WriteLine();
}

public static String ConvertUPC(string arg) {
return arg + " -> " + getUPC(arg);
}
}
}

0 comments:

Content © didge

About Me

didge is my professional nickname, it's short for digital dave