cdigit
Version:
Collection of check digit algorithms implemented in JavaScript
86 lines (85 loc) • 3.03 kB
JavaScript
/**
* cdigit
*
* @copyright 2018-2023 LiosK
* @license (MIT OR Apache-2.0)
*/
class Verhoeff {
constructor(name, longName) {
this.name = name;
this.longName = longName;
/** The Verhoeff multiplication table. */
this.d = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
[2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
[3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
[4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
[5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
[6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
[7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
[8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
];
/** The Verhoeff permutation table. */
this.p = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
[5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
[8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
[9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
[4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
[2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
[7, 0, 4, 6, 9, 1, 3, 2, 5, 8],
];
/** The Verhoeff inverse table. */
this.inv = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9];
}
computeFromNumVals(ns) {
if (ns.length === 0) {
throw new SyntaxError("string to be protected is empty");
}
else if (ns.some((e) => e < 0 || e > 9 || !Number.isInteger(e))) {
throw new SyntaxError("invalid numerical value detected");
}
// as if: `ns.push(0); let c = 0;` and finished first loop where i == 0
let c = this.d[0][this.p[0][0]];
for (let i = 1, len = ns.length; i <= len; i += 1) {
c = this.d[c][this.p[i & 7][ns[len - i]]];
}
return [this.inv[c]];
}
compute(s) {
const ds = String(s).replace(/[^0-9]/g, "");
const ns = [...ds].map(Number);
return String(this.computeFromNumVals(ns)[0]);
}
parse(s) {
const m = String(s).match(/^(.*)([0-9])$/s);
if (m != null) {
return [m[1], m[2]];
}
else {
throw new SyntaxError("could not find check character(s)");
}
}
generate(s) {
return `${s}${this.compute(s)}`;
}
validate(s) {
const [bare, cc] = this.parse(s);
return this.compute(bare) === cc;
}
}
/**
* The Verhoeff algorithm implementation.
*
* Note: There is not a firm consensus on the direction (left to right or right
* to left) in which a Verhoeff calculator scans numeric text to construct an
* input digit sequence. This implementation is hard coded to read a string from
* right to left and append the check digit at the rightmost position, which is
* a consistent behavior with other popular implementations. Reverse the input
* string before calling this class' methods if you need to interpret a string
* from left to right.
*/
export const verhoeff = new Verhoeff("verhoeff", "Verhoeff Algorithm");