Skip to content

Commit ee90715

Browse files
committed
Adding check digit utilities
1 parent 3b574b6 commit ee90715

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
group = 'com.labelzoom.api'
9-
version = '1.3.0'
9+
version = '1.3.1'
1010

1111
java {
1212
sourceCompatibility = JavaVersion.VERSION_1_8
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.labelzoom.api.util;
2+
3+
public class CheckDigitUtils
4+
{
5+
public enum CheckDigitType
6+
{
7+
MOD10,
8+
}
9+
10+
public static int getCheckDigit(final String barcode, final CheckDigitType type)
11+
{
12+
switch (type)
13+
{
14+
case MOD10: return getMod10CheckDigit(barcode);
15+
default: throw new IllegalArgumentException("Invalid check digit type");
16+
}
17+
}
18+
19+
/**
20+
* <p>
21+
* <a href="https://www.axicon.com/checkdigitcalculator.html">MOD10 Check Digit Calculator</a>
22+
* </p>
23+
*
24+
* <p>
25+
* How to calculate your check digit yourself
26+
* </p>
27+
*
28+
* <p>
29+
* Example barcode number: 501234576421
30+
* </p>
31+
*
32+
* <p>
33+
* Step 1: add together all alternate numbers starting from the right<br>
34+
* <code>5 0 1 2 3 4 5 7 6 4 2 1</code><br>
35+
* <code>0 + 2 + 4 + 7 + 4 + 1 = 18</code>
36+
* </p>
37+
*
38+
* <p>
39+
* Step 2: multiply the answer by 3<br>
40+
* <code>18 x 3 = 54</code>
41+
* </p>
42+
*
43+
* <p>
44+
* Step 3: now add together the remaining numbers<br>
45+
* <code>5 0 1 2 3 4 5 7 6 4 2 1</code><br>
46+
* <code>5 + 1 + 3 + 5 + 6 + 2 = 22</code>
47+
* </p>
48+
*
49+
* <p>
50+
* Step 4: add step 2 and 3 together<br>
51+
* <code>54 + 22 = 76</code>
52+
* </p>
53+
*
54+
* <p>
55+
* Step 5: the difference between step 4 and the next 10th number:<br>
56+
* <code>76 + 4 = 80</code><br>
57+
* Check digit = <code>4</code>
58+
* </p>
59+
*
60+
* @param barcode the barcode data
61+
* @return the check digit
62+
*/
63+
private static int getMod10CheckDigit(final String barcode)
64+
{
65+
char[] digits = barcode.toCharArray();
66+
/* Sum odds and evens separately so that we only perform one multiplication. In practice, one large
67+
* multiplication was faster than several small multiplications
68+
*/
69+
int evens = 0;
70+
int odds = 0;
71+
boolean isEven = false; // Use alternating boolean variable rather than modular division (e.g., i % 2)
72+
for (int i = digits.length - 1; i >= 0; i--)
73+
{
74+
if (isEven = !isEven) // Invert and update value as we read it. Ignore IntelliJ, it doesn't appreciate my l33tness
75+
{
76+
evens += Character.getNumericValue(digits[i]);
77+
}
78+
else
79+
{
80+
odds += Character.getNumericValue(digits[i]);
81+
}
82+
}
83+
return 10 - (((evens * 3) + odds) % 10);
84+
}
85+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.labelzoom.api.util;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.junit.jupiter.api.Assertions.assertEquals;
6+
7+
class CheckDigitUtilsTests
8+
{
9+
@Test
10+
void testAxiconExample() { assertEquals(4, CheckDigitUtils.getCheckDigit("501234576421", CheckDigitUtils.CheckDigitType.MOD10)); }
11+
12+
@Test
13+
void testSsccExample() { assertEquals(8, CheckDigitUtils.getCheckDigit("0000123456000000001", CheckDigitUtils.CheckDigitType.MOD10)); }
14+
15+
@Test
16+
void testCode128Example() { assertEquals(8, CheckDigitUtils.getCheckDigit("0008100887950411637", CheckDigitUtils.CheckDigitType.MOD10)); }
17+
}

0 commit comments

Comments
 (0)