@@ -2,34 +2,57 @@ import assertString from './util/assertString';
22
33const isin = / ^ [ A - Z ] { 2 } [ 0 - 9 A - 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
612export 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}
0 commit comments