I just discovered a bug in the check digit calculation, fixed below. Essentially, the check digit is only subtracted from 10 if the sum_of_totals % 10 is greater than 0. I'm sorry for any inconvenience!
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:
- Sum the digits in all odd positions, and multiply the result by 3.
- Sum the digits in all even positions.
- Sum the totals calculated in steps 2 and 3.
- *UPDATED* Check digit is sum_of_totals % 10 > 0 ? 10 - (sum_of_totals % 10) : 0
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; }
// *UPDATED* char checksumDigit = '0'; checksum %= 10; if(checksum > 0) checksumDigit += (char)(10 - checksum); 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); } } }
No comments:
Post a Comment