1+ const addressRegex = / ^ [ A - Z ] + \d + $ / ;
12// =========================================================================
23// Column Letter to Number conversion
34const colCache = {
@@ -29,6 +30,7 @@ const colCache = {
2930 'Y' ,
3031 'Z' ,
3132 ] ,
33+ _l2nFill : 0 ,
3234 _l2n : { } ,
3335 _n2l : [ ] ,
3436 _level ( n ) {
@@ -48,18 +50,20 @@ const colCache = {
4850 let l3 ;
4951 let n = 1 ;
5052 if ( level >= 4 ) {
51- throw new Error ( ` Out of bounds. Excel supports columns from 1 to 16384` ) ;
53+ throw new Error ( ' Out of bounds. Excel supports columns from 1 to 16384' ) ;
5254 }
53- if ( level >= 1 ) {
55+ if ( this . _l2nFill < 1 && level >= 1 ) {
5456 while ( n <= 26 ) {
5557 c = this . _dictionary [ n - 1 ] ;
5658 this . _n2l [ n ] = c ;
5759 this . _l2n [ c ] = n ;
5860 n ++ ;
5961 }
62+ this . _l2nFill = 1 ;
6063 }
61- if ( level >= 2 ) {
62- while ( n <= 26 + 26 * 26 ) {
64+ if ( this . _l2nFill < 2 && level >= 2 ) {
65+ n = 27 ;
66+ while ( n <= 26 + ( 26 * 26 ) ) {
6367 v = n - ( 26 + 1 ) ;
6468 l1 = v % 26 ;
6569 l2 = Math . floor ( v / 26 ) ;
@@ -68,10 +72,12 @@ const colCache = {
6872 this . _l2n [ c ] = n ;
6973 n ++ ;
7074 }
75+ this . _l2nFill = 2 ;
7176 }
72- if ( level >= 3 ) {
77+ if ( this . _l2nFill < 3 && level >= 3 ) {
78+ n = 26 + ( 26 * 26 ) + 1 ;
7379 while ( n <= 16384 ) {
74- v = n - ( 26 * 26 + 26 + 1 ) ;
80+ v = n - ( ( 26 * 26 ) + 26 + 1 ) ;
7581 l1 = v % 26 ;
7682 l2 = Math . floor ( v / 26 ) % 26 ;
7783 l3 = Math . floor ( v / ( 26 * 26 ) ) ;
@@ -80,6 +86,7 @@ const colCache = {
8086 this . _l2n [ c ] = n ;
8187 n ++ ;
8288 }
89+ this . _l2nFill = 3 ;
8390 }
8491 } ,
8592 l2n ( l ) {
@@ -107,41 +114,63 @@ const colCache = {
107114
108115 // check if value looks like an address
109116 validateAddress ( value ) {
110- if ( ! value . match ( / ^ [ A - Z ] + \d + $ / ) ) {
117+ if ( ! addressRegex . test ( value ) ) {
111118 throw new Error ( `Invalid Address: ${ value } ` ) ;
112119 }
113120 return true ;
114121 } ,
115122
116123 // convert address string into structure
117124 decodeAddress ( value ) {
118- const addr = this . _hash [ value ] ;
125+ const addr = value . length < 5 && this . _hash [ value ] ;
119126 if ( addr ) {
120127 return addr ;
121128 }
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 ) ;
129+ let hasCol = false ;
130+ let col = '' ;
131+ let colNumber = 0 ;
132+ let hasRow = false ;
133+ let row = '' ;
134+ let rowNumber = 0 ;
135+ for ( let i = 0 , char ; i < value . length ; i ++ ) {
136+ char = value . charCodeAt ( i ) ;
137+ // col should before row
138+ if ( ! hasRow && char >= 65 && char <= 90 ) {
139+ // 65 = 'A'.charCodeAt(0)
140+ // 90 = 'Z'.charCodeAt(0)
141+ hasCol = true ;
142+ col += value [ i ] ;
143+ // colNumber starts from 1
144+ colNumber = ( colNumber * 26 ) + char - 64 ;
145+ } else if ( char >= 48 && char <= 57 ) {
146+ // 48 = '0'.charCodeAt(0)
147+ // 57 = '9'.charCodeAt(0)
148+ hasRow = true ;
149+ row += value [ i ] ;
150+ // rowNumber starts from 0
151+ rowNumber = ( rowNumber * 10 ) + char - 48 ;
152+ } else if ( hasRow && hasCol && char !== 36 ) {
153+ // 36 = '$'.charCodeAt(0)
154+ break ;
155+ }
156+ }
157+ if ( ! hasCol ) {
158+ colNumber = undefined ;
159+ } else if ( colNumber > 16384 ) {
160+ throw new Error ( `Out of bounds. Invalid column letter: ${ col } ` ) ;
128161 }
129- const matchRow = value . match ( / \d + / ) ;
130- let row ;
131- let rowNumber ;
132- if ( matchRow ) {
133- row = matchRow [ 0 ] ;
134- rowNumber = parseInt ( row , 10 ) ;
162+ if ( ! hasRow ) {
163+ rowNumber = undefined ;
135164 }
136165
137166 // in case $row$col
138- value = ( col || '' ) + ( row || '' ) ;
167+ value = col + row ;
139168
140169 const address = {
141170 address : value ,
142171 col : colNumber ,
143172 row : rowNumber ,
144- $col$row : `$${ col || '' } $${ row || '' } ` ,
173+ $col$row : `$${ col } $${ row } ` ,
145174 } ;
146175
147176 // mem fix - cache only the tl 100x100 square
0 commit comments