3
3
//------------------------------------------------------------------------------
4
4
5
5
import { HeaderIndex , Position , RangePart } from "../types" ;
6
+ import { TokenizingChars } from "./misc" ;
6
7
7
8
/**
8
9
* Convert a (col) number to the corresponding letter.
@@ -28,13 +29,17 @@ export function lettersToNumber(letters: string): number {
28
29
let result = 0 ;
29
30
const l = letters . length ;
30
31
for ( let i = 0 ; i < l ; i ++ ) {
31
- const charCode = letters . charCodeAt ( i ) ;
32
- const colIndex = charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96 ;
32
+ const colIndex = charToNumber ( letters [ i ] ) ;
33
33
result = result * 26 + colIndex ;
34
34
}
35
35
return result - 1 ;
36
36
}
37
37
38
+ function charToNumber ( char : string ) {
39
+ const charCode = char . charCodeAt ( 0 ) ;
40
+ return charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96 ;
41
+ }
42
+
38
43
function isCharALetter ( char : string ) {
39
44
return ( char >= "A" && char <= "Z" ) || ( char >= "a" && char <= "z" ) ;
40
45
}
@@ -43,6 +48,40 @@ function isCharADigit(char: string) {
43
48
return char >= "0" && char <= "9" ;
44
49
}
45
50
51
+ // we limit the max column to 3 letters and max row to 7 digits for performance reasons
52
+ export const MAX_COL = lettersToNumber ( "ZZZ" ) ;
53
+ export const MAX_ROW = 9999998 ;
54
+
55
+ export function consumeSpaces ( chars : TokenizingChars ) {
56
+ while ( chars . current === " " ) {
57
+ chars . advanceBy ( 1 ) ;
58
+ }
59
+ }
60
+
61
+ export function consumeLetters ( chars : TokenizingChars ) : number {
62
+ if ( chars . current === "$" ) chars . advanceBy ( 1 ) ;
63
+ if ( ! chars . current || ! isCharALetter ( chars . current ) ) {
64
+ return - 1 ;
65
+ }
66
+ let colCoordinate = 0 ;
67
+ while ( chars . current && isCharALetter ( chars . current ) ) {
68
+ colCoordinate = colCoordinate * 26 + charToNumber ( chars . shift ( ) ) ;
69
+ }
70
+ return colCoordinate ;
71
+ }
72
+
73
+ export function consumeDigits ( chars : TokenizingChars ) : number {
74
+ if ( chars . current === "$" ) chars . advanceBy ( 1 ) ;
75
+ if ( ! chars . current || ! isCharADigit ( chars . current ) ) {
76
+ return - 1 ;
77
+ }
78
+ let num = 0 ;
79
+ while ( chars . current && isCharADigit ( chars . current ) ) {
80
+ num = num * 10 + Number ( chars . shift ( ) ) ;
81
+ }
82
+ return num ;
83
+ }
84
+
46
85
/**
47
86
* Convert a "XC" coordinate to cartesian coordinates.
48
87
*
@@ -53,37 +92,21 @@ function isCharADigit(char: string) {
53
92
* Note: it also accepts lowercase coordinates, but not fixed references
54
93
*/
55
94
export function toCartesian ( xc : string ) : Position {
56
- xc = xc . trim ( ) ;
57
-
58
- let letterPart = "" ;
59
- let numberPart = "" ;
60
- let i = 0 ;
95
+ const chars = new TokenizingChars ( xc ) ;
61
96
62
- // Process letter part
63
- if ( xc [ i ] === "$" ) i ++ ;
64
- while ( i < xc . length && isCharALetter ( xc [ i ] ) ) {
65
- letterPart += xc [ i ++ ] ;
66
- }
97
+ consumeSpaces ( chars ) ;
98
+ const letterPart = consumeLetters ( chars ) ;
67
99
68
- if ( letterPart . length === 0 || letterPart . length > 3 ) {
69
- // limit to max 3 letters for performance reasons
100
+ if ( letterPart === - 1 || ! chars . current ) {
70
101
throw new Error ( `Invalid cell description: ${ xc } ` ) ;
71
102
}
72
103
73
- // Process number part
74
- if ( xc [ i ] === "$" ) i ++ ;
75
- while ( i < xc . length && isCharADigit ( xc [ i ] ) ) {
76
- numberPart += xc [ i ++ ] ;
77
- }
78
-
79
- if ( i !== xc . length || numberPart . length === 0 || numberPart . length > 7 ) {
80
- // limit to max 7 numbers for performance reasons
81
- throw new Error ( `Invalid cell description: ${ xc } ` ) ;
82
- }
104
+ const num = consumeDigits ( chars ) ;
105
+ consumeSpaces ( chars ) ;
83
106
84
- const col = lettersToNumber ( letterPart ) ;
85
- const row = Number ( numberPart ) - 1 ;
86
- if ( isNaN ( row ) ) {
107
+ const col = letterPart - 1 ;
108
+ const row = num - 1 ;
109
+ if ( ! chars . isOver ( ) || col > MAX_COL || row > MAX_ROW ) {
87
110
throw new Error ( `Invalid cell description: ${ xc } ` ) ;
88
111
}
89
112
return { col, row } ;
0 commit comments