Skip to content

Instantly share code, notes, and snippets.

@skinofstars
Created June 14, 2021 18:40
Show Gist options
  • Save skinofstars/ac0860b81654b5a321982e1451f28207 to your computer and use it in GitHub Desktop.
Save skinofstars/ac0860b81654b5a321982e1451f28207 to your computer and use it in GitHub Desktop.
USPS Traditional ACS keyline MOD 10 check digit
const keylinesChecks: [string, number][] = [
['JLSTMS6796', 9],
['TMS1112/62', 3],
['218XN91LMS', 4],
['OTUBIKALAM', 8],
['ABC999NN//3', 2],
['ANIT 028', 1],
['0012 ////', 8],
['811N IS00 0111', 9],
['OTUB IKAL AM', 8],
['SEIR AMT', 4],
['1402 4981 49', 0],
['AEIO UW', 0],
['1234 5678 90', 7],
['DCS1 402', 0],
['0987 6543 21', 3],
];
describe.each(keylinesChecks)('Creating a keyline check digit', (input, expected) => {
it(`should produce check digit ${expected} for keyline ${input}`, () => {
expect(getUSPSKeylineCheckDigit(input)).toEqual(expected);
});
});
const RADIX_DECIMAL = 10;
const RADIX_HEX = 16;
const isNumber = (n: string): boolean => !isNaN(parseInt(n, RADIX_DECIMAL));
// Convert ascii characters to numeric values by zeroing out all but the lower four bits
const acsCharToInt = (c: string): number =>
parseInt(c.charCodeAt(0).toString(RADIX_HEX).slice(-1), RADIX_HEX);
const isOdd = (n: number): boolean => n % 2 === 1;
// Reduce by summing figures until single figure
const sumDoubleDigits = (n: number): number => {
if (n < 10) return n;
const [a, b] = n
.toString()
.split('')
.map((v) => parseInt(v, RADIX_DECIMAL));
return sumDoubleDigits(a + b);
};
const lastFigure = (n: number): number =>
parseInt(n.toString().split('').slice(-1).join(), RADIX_DECIMAL);
/**
* For generating a USPS Traditional ACS keyline check digit
* https://postalpro.usps.com/mnt/glusterfs/2019-10/TraditionalACSTechnicalGuide.pdf
*
* @param keyline A string for our own reference
* @returns USPS ACS Traditional keyline MOD 10 check digit
*/
export function getUSPSKeylineCheckDigit(keyline: string) {
const keySum = keyline
// Remove whitespace
.replace(/\s+/g, '')
.split('')
// Convert any letters to ACS defined numerical equivalent
.map((val) => (isNumber(val) ? parseInt(val, RADIX_DECIMAL) : acsCharToInt(val)))
// Multiply odd position keys by weighting factor of 2 ... a.k.a. double it
.map((val, idx) => (isOdd(idx + 1) ? val * 2 : val))
// Reduce double to single digits
.map((val) => sumDoubleDigits(val))
// Sum
.reduce((a, b) => a + b, 0);
// so we don't subtract 0 from 10
if (lastFigure(keySum) === 0) return 0;
return 10 - lastFigure(keySum);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment