From 0711da12a2e706bf3275371b257c5e635995e719 Mon Sep 17 00:00:00 2001 From: Owen Barton Date: Thu, 26 Oct 2017 15:43:04 -0700 Subject: [PATCH] Make utils functions public and add a couple (TODO tests and docs). --- cell.go | 2 +- utils.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++-- utils_test.go | 14 ++++++------- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/cell.go b/cell.go index df5fe48..554cebd 100644 --- a/cell.go +++ b/cell.go @@ -11,5 +11,5 @@ type Cell struct { // Pos returns the cell's position like "A1" func (cell *Cell) Pos() string { - return numberToLetter(int(cell.Column)+1) + fmt.Sprintf("%d", cell.Row+1) + return NumberToLetter(int(cell.Column)+1) + fmt.Sprintf("%d", cell.Row+1) } diff --git a/utils.go b/utils.go index 5d77798..baec132 100644 --- a/utils.go +++ b/utils.go @@ -1,9 +1,62 @@ package spreadsheet -func numberToLetter(num int) string { +import ( + "errors" + "regexp" + "strconv" +) + +func NumberToLetter(num int) string { if num <= 0 { return "" } - return numberToLetter(int((num-1)/26)) + string(byte(65+(num-1)%26)) + return NumberToLetter(int((num-1)/26)) + string(byte(65+(num-1)%26)) +} + +func LetterToNumber(letter string) (int, error) { + var total int + l := len(letter) + if l >= 14 { + return 0, errors.New("only references shorter than 14 characters are supported") + } + for n, c := range []byte(letter) { + v := int(byte(c) - 65) + // On invalid value, just return zero. + if (v < 0) || (v > 25) { + return 0, errors.New("expecting upper case A-Z only") + } + // Calculate 26 to the power of the place value. + r := 1 + for i := 1; i < l-n; i++ { + r *= 26 + } + // Multiply by the character value starting from A=1 and add to total. + total += r * ((v % 26) + 1) + } + return total, nil +} + +func ParseReferenceRange(ref string) (sheet string, x1, y1, x2, y2 int, err error) { + re := regexp.MustCompile("^'?([^!]+?)'?[!]([A-Z]+)([0-9]+):([A-Z]+)([0-9]+)$") + xyparts := re.FindAllStringSubmatch(ref, -1) + if xyparts == nil { + err = errors.New("can't parse sheet reference") + return + } + sheet = xyparts[0][1] + x1, err = LetterToNumber(xyparts[0][2]) + if err != nil { + return + } + y1, err = strconv.Atoi(xyparts[0][3]) + if err != nil { + return + } + x2, err = LetterToNumber(xyparts[0][4]) + if err != nil { + return + } + y2, err = strconv.Atoi(xyparts[0][5]) + return } diff --git a/utils_test.go b/utils_test.go index ad54c55..5be8e22 100644 --- a/utils_test.go +++ b/utils_test.go @@ -8,13 +8,13 @@ import ( func TestNumberToLetter(t *testing.T) { assert := assert.New(t) - assert.Equal("C", numberToLetter(3)) - assert.Equal("Z", numberToLetter(26)) - assert.Equal("AB", numberToLetter(28)) - assert.Equal("AZ", numberToLetter(52)) - assert.Equal("AAC", numberToLetter(705)) - assert.Equal("YZ", numberToLetter(676)) - assert.Equal("ZA", numberToLetter(677)) + assert.Equal("C", NumberToLetter(3)) + assert.Equal("Z", NumberToLetter(26)) + assert.Equal("AB", NumberToLetter(28)) + assert.Equal("AZ", NumberToLetter(52)) + assert.Equal("AAC", NumberToLetter(705)) + assert.Equal("YZ", NumberToLetter(676)) + assert.Equal("ZA", NumberToLetter(677)) } func BenchmarkNumberToLetter(b *testing.B) {