summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Lemon <lemon@matthewlemon.com>2019-12-03 17:11:52 +0000
committerMatthew Lemon <lemon@matthewlemon.com>2019-12-03 17:11:52 +0000
commit30d510fc62ed7aec90820835926a784744c51d7f (patch)
tree12dbe08033673153308351f81e4e66566548a9cf
initial commit
-rw-r--r--coords.go68
-rw-r--r--coords_test.go99
2 files changed, 167 insertions, 0 deletions
diff --git a/coords.go b/coords.go
new file mode 100644
index 0000000..ee13dba
--- /dev/null
+++ b/coords.go
@@ -0,0 +1,68 @@
+/*
+coords calculates coordinates for spreadsheets.
+*/
+package coords
+
+import (
+ "errors"
+ "fmt"
+)
+
+const (
+ maxCols = 16384
+ maxAlphabets = (maxCols / 26) - 1
+)
+
+// ColAlpha returns an alpha representation of a column index.
+// index is an integer - ColAlpha(0) returns "A", etc.
+func ColIndexToAlpha(index int) (string, error) {
+ max := len(colstream) - 1
+ if index <= max {
+ return colstream[index], nil
+ } else {
+ msg := fmt.Sprintf("cannot have more than %d columns", max)
+ return "", errors.New(msg)
+ }
+}
+
+var colstream = cols(maxAlphabets)
+
+// ColLettersToIndex converts an alpha column
+// reference to a zero-based numeric column identifier.
+func ColAlphaToIndex(letters string) (int, error) {
+ max := len(colstream) - 1
+ for i, v := range colstream {
+ if i > max {
+ msg := fmt.Sprintf("Cannot exceed maximum of %d", max)
+ return 0, errors.New(msg)
+ }
+ if v == letters {
+ return i, nil
+ }
+ }
+ return 0, errors.New("Cannot find requested string.")
+}
+
+//alphabet generates all the letters of the alphabet.
+func alphabet() []string {
+ letters := make([]string, 26)
+ for idx := range letters {
+ letters[idx] = string('A' + byte(idx))
+ }
+ return letters
+}
+
+//cols generates the alpha column component of Excel cell references
+//Adds n alphabets to the first (A..Z) alphabet.
+func cols(n int) []string {
+ out := alphabet()
+ alen := len(out)
+ tmp := make([]string, alen)
+ copy(tmp, out)
+ for cycle := 0; cycle < n; cycle++ {
+ for y := 0; y < alen; y++ {
+ out = append(out, out[(cycle+2)-2]+tmp[y])
+ }
+ }
+ return out
+}
diff --git a/coords_test.go b/coords_test.go
new file mode 100644
index 0000000..8f8f865
--- /dev/null
+++ b/coords_test.go
@@ -0,0 +1,99 @@
+package coords
+
+import (
+ "testing"
+)
+
+func TestAlphaStream(t *testing.T) {
+ if colstream[26] != "AA" {
+ t.Errorf("The test expected AA, got %v.", colstream[26])
+ }
+ if len(colstream) > maxCols {
+ t.Errorf(`Number of columns in alphastream exceeds Excel maximum.
+ alphastream contains %d, maxCols is %d`, len(colstream), maxCols)
+ }
+}
+
+func TestAlphaSingle(t *testing.T) {
+ ab := alphabet()
+ if ab[0] != "A" {
+ t.Errorf("The test expected A, got %v.", ab[0])
+ }
+ if ab[1] != "B" {
+ t.Errorf("The test expected B, got %v.", ab[1])
+ }
+ if ab[25] != "Z" {
+ t.Errorf("The test expected Z, got %v.", ab[25])
+ }
+}
+
+func TestAlphas(t *testing.T) {
+ a := 2 // two alphabets long
+ ecs := cols(a)
+ cases := []struct {
+ col int
+ val string
+ }{
+ {0, "A"},
+ {25, "Z"},
+ {26, "AA"},
+ {52, "BA"},
+ }
+ for _, c := range cases {
+ // we're making sure we can pass that index
+ r := 26 * a
+ if c.col > r {
+ t.Fatalf("Cannot use %d as index to array of %d", c.col, r)
+ }
+ if got := ecs[c.col]; got != c.val {
+ t.Errorf("The test expected ecs[%d] to be %s - got %s.",
+ c.col, c.val, ecs[c.col])
+ }
+ }
+}
+
+func TestCollectLetters(t *testing.T) {
+ cases := []struct {
+ alpha string
+ index int
+ }{
+ {"XEZ", 16379},
+ {"XEY", 16378},
+ {"XEX", 16377},
+ {"A", 0},
+ {"B", 1},
+ {"C", 2},
+ {"AA", 26},
+ }
+ for _, c := range cases {
+ s, err := ColAlphaToIndex(c.alpha)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if s != c.index {
+ t.Errorf("Expected %d to return %s, instead it returned %d", c.index, c.alpha, s)
+ }
+
+ }
+}
+
+func TestGetColApha(t *testing.T) {
+ cases := []struct {
+ index int
+ alpha string
+ }{
+ {0, "A"},
+ {1, "B"},
+ {2, "C"},
+ {16377, "XEX"},
+ }
+ for _, c := range cases {
+ s, err := ColIndexToAlpha(c.index)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if s != c.alpha {
+ t.Errorf("Expected %s, got %s\n", c.alpha, s)
+ }
+ }
+}