@@ -29,6 +29,7 @@ const colCache = {
2929 'Y' ,
3030 'Z' ,
3131 ] ,
32+ _l2nFill : 0 ,
3233 _l2n : { } ,
3334 _n2l : [ ] ,
3435 _level ( n ) {
@@ -48,18 +49,20 @@ const colCache = {
4849 let l3 ;
4950 let n = 1 ;
5051 if ( level >= 4 ) {
51- throw new Error ( ` Out of bounds. Excel supports columns from 1 to 16384` ) ;
52+ throw new Error ( ' Out of bounds. Excel supports columns from 1 to 16384' ) ;
5253 }
53- if ( level >= 1 ) {
54+ if ( this . _l2nFill < 1 && level >= 1 ) {
5455 while ( n <= 26 ) {
5556 c = this . _dictionary [ n - 1 ] ;
5657 this . _n2l [ n ] = c ;
5758 this . _l2n [ c ] = n ;
5859 n ++ ;
5960 }
61+ this . _l2nFill = 1 ;
6062 }
61- if ( level >= 2 ) {
62- while ( n <= 26 + 26 * 26 ) {
63+ if ( this . _l2nFill < 2 && level >= 2 ) {
64+ n = 27 ;
65+ while ( n <= 26 + ( 26 * 26 ) ) {
6366 v = n - ( 26 + 1 ) ;
6467 l1 = v % 26 ;
6568 l2 = Math . floor ( v / 26 ) ;
@@ -68,10 +71,12 @@ const colCache = {
6871 this . _l2n [ c ] = n ;
6972 n ++ ;
7073 }
74+ this . _l2nFill = 2 ;
7175 }
72- if ( level >= 3 ) {
76+ if ( this . _l2nFill < 3 && level >= 3 ) {
77+ n = 26 + ( 26 * 26 ) + 1 ;
7378 while ( n <= 16384 ) {
74- v = n - ( 26 * 26 + 26 + 1 ) ;
79+ v = n - ( ( 26 * 26 ) + 26 + 1 ) ;
7580 l1 = v % 26 ;
7681 l2 = Math . floor ( v / 26 ) % 26 ;
7782 l3 = Math . floor ( v / ( 26 * 26 ) ) ;
@@ -80,6 +85,7 @@ const colCache = {
8085 this . _l2n [ c ] = n ;
8186 n ++ ;
8287 }
88+ this . _l2nFill = 3 ;
8389 }
8490 } ,
8591 l2n ( l ) {
@@ -107,41 +113,95 @@ const colCache = {
107113
108114 // check if value looks like an address
109115 validateAddress ( value ) {
110- if ( ! value . match ( / ^ [ A - Z ] + \d + $ / ) ) {
116+ // if (!value.match(/^[A-Z]+\d+$/))
117+ // throw new Error(`Invalid Address: ${value}`);
118+ let isValid = true ;
119+ let hasRow = false ;
120+ let hasCol = false ;
121+ // 65 = 'A'.charCodeAt(0)
122+ // 90 = 'Z'.charCodeAt(0)
123+ // 48 = '0'.charCodeAt(0)
124+ // 57 = '9'.charCodeAt(0)
125+ for ( let i = 0 , char ; i < value . length ; i ++ ) {
126+ if ( ! isValid ) {
127+ break ;
128+ }
129+ char = value . charCodeAt ( i ) ;
130+ if ( ! hasRow ) {
131+ if ( char >= 65 && char <= 90 ) {
132+ hasCol = true ;
133+ } else if ( char >= 48 && char <= 57 ) {
134+ if ( ! hasCol ) {
135+ isValid = false ;
136+ break ;
137+ }
138+ hasRow = true ;
139+ } else {
140+ isValid = false ;
141+ break ;
142+ }
143+ } else if ( ! ( char >= 48 && char <= 57 ) ) {
144+ isValid = false ;
145+ break ;
146+ }
147+ }
148+ if ( ! isValid || ! hasRow || ! hasCol ) {
111149 throw new Error ( `Invalid Address: ${ value } ` ) ;
112150 }
113151 return true ;
114152 } ,
115153
116154 // convert address string into structure
117155 decodeAddress ( value ) {
118- const addr = this . _hash [ value ] ;
156+ const addr = value . length < 5 && this . _hash [ value ] ;
119157 if ( addr ) {
120158 return addr ;
121159 }
122- const matchCol = value . match ( / [ A - Z ] + / ) ;
123- let col ;
124- let colNumber ;
125- if ( matchCol ) {
126- col = matchCol [ 0 ] ;
127- colNumber = this . l2n ( col ) ;
160+ let hasCol = false ;
161+ let col = '' ;
162+ let colNumber = 0 ;
163+ let hasRow = false ;
164+ let row = '' ;
165+ let rowNumber = 0 ;
166+ for ( let i = 0 , char ; i < value . length ; i ++ ) {
167+ char = value . charCodeAt ( i ) ;
168+ // col should before row
169+ if ( ! hasRow && char >= 65 && char <= 90 ) {
170+ // 65 = 'A'.charCodeAt(0)
171+ // 90 = 'Z'.charCodeAt(0)
172+ hasCol = true ;
173+ col += value [ i ] ;
174+ // colNumber starts from 1
175+ colNumber = ( colNumber * 26 ) + char - 64 ;
176+ } else if ( char >= 48 && char <= 57 ) {
177+ // 48 = '0'.charCodeAt(0)
178+ // 57 = '9'.charCodeAt(0)
179+ hasRow = true ;
180+ row += value [ i ] ;
181+ // rowNumber starts from 0
182+ rowNumber = ( rowNumber * 10 ) + char - 48 ;
183+ } else if ( hasRow && hasCol && char !== 36 ) {
184+ // 36 = '$'.charCodeAt(0)
185+ break ;
186+ }
187+ }
188+ if ( ! hasCol ) {
189+ colNumber = undefined ;
190+ } else if ( colNumber > 16384 ) {
191+ throw new Error ( `Out of bounds. Invalid column letter: ${ col } ` ) ;
128192 }
129- const matchRow = value . match ( / \d + / ) ;
130- let row ;
131- let rowNumber ;
132- if ( matchRow ) {
133- row = matchRow [ 0 ] ;
134- rowNumber = parseInt ( row , 10 ) ;
193+ if ( ! hasRow ) {
194+ rowNumber = undefined ;
135195 }
136196
137197 // in case $row$col
138- value = ( col || '' ) + ( row || '' ) ;
198+ value = col + row ;
139199
140200 const address = {
141201 address : value ,
142202 col : colNumber ,
143203 row : rowNumber ,
144- $col$row : `$${ col || '' } $${ row || '' } ` ,
204+ $col$row : `$${ col } $${ row } ` ,
145205 } ;
146206
147207 // mem fix - cache only the tl 100x100 square
0 commit comments