Skip to content

Commit c33fca6

Browse files
authored
fix(isISIN): optimization (#1633)
* optimize isISIN speed + gc * add aapl ISIN * comment and reference
1 parent 2ef84e4 commit c33fca6

2 files changed

Lines changed: 41 additions & 17 deletions

File tree

src/lib/isISIN.js

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,57 @@ import assertString from './util/assertString';
22

33
const isin = /^[A-Z]{2}[0-9A-Z]{9}[0-9]$/;
44

5+
// this link details how the check digit is calculated:
6+
// https://www.isin.org/isin-format/. it is a little bit
7+
// odd in that it works with digits, not numbers. in order
8+
// to make only one pass through the ISIN characters, the
9+
// each alpha character is handled as 2 characters within
10+
// the loop.
511

612
export default function isISIN(str) {
713
assertString(str);
814
if (!isin.test(str)) {
915
return false;
1016
}
1117

12-
const checksumStr = str.replace(/[A-Z]/g, character => (parseInt(character, 36)));
13-
18+
let double = true;
1419
let sum = 0;
15-
let digit;
16-
let tmpNum;
17-
let shouldDouble = true;
18-
for (let i = checksumStr.length - 2; i >= 0; i--) {
19-
digit = checksumStr.substring(i, (i + 1));
20-
tmpNum = parseInt(digit, 10);
21-
if (shouldDouble) {
22-
tmpNum *= 2;
23-
if (tmpNum >= 10) {
24-
sum += tmpNum + 1;
25-
} else {
26-
sum += tmpNum;
20+
// convert values
21+
for (let i = str.length - 2; i >= 0; i--) {
22+
if (str[i] >= 'A' && str[i] <= 'Z') {
23+
const value = str[i].charCodeAt(0) - 55;
24+
const lo = value % 10;
25+
const hi = Math.trunc(value / 10);
26+
// letters have two digits, so handle the low order
27+
// and high order digits separately.
28+
for (const digit of [lo, hi]) {
29+
if (double) {
30+
if (digit >= 5) {
31+
sum += 1 + ((digit - 5) * 2);
32+
} else {
33+
sum += digit * 2;
34+
}
35+
} else {
36+
sum += digit;
37+
}
38+
double = !double;
2739
}
2840
} else {
29-
sum += tmpNum;
41+
const digit = str[i].charCodeAt(0) - '0'.charCodeAt(0);
42+
if (double) {
43+
if (digit >= 5) {
44+
sum += 1 + ((digit - 5) * 2);
45+
} else {
46+
sum += digit * 2;
47+
}
48+
} else {
49+
sum += digit;
50+
}
51+
double = !double;
3052
}
31-
shouldDouble = !shouldDouble;
3253
}
3354

34-
return parseInt(str.substr(str.length - 1), 10) === (10000 - sum) % 10;
55+
const check = (Math.trunc(((sum + 9) / 10)) * 10) - sum;
56+
57+
return +str[str.length - 1] === check;
3558
}

test/validators.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4845,6 +4845,7 @@ describe('Validators', () => {
48454845
'GB0001411924',
48464846
'DE000WCH8881',
48474847
'PLLWBGD00016',
4848+
'US0378331005',
48484849
],
48494850
invalid: [
48504851
'DE000BAY0018',

0 commit comments

Comments
 (0)