summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormbresson <matthieu.bresson@kapptivate.com>2018-01-19 17:32:54 +0800
committermbresson <matthieu.bresson@kapptivate.com>2018-01-19 17:49:09 +0800
commit317ef65381b179b863dcd6b1f5479cc576a8376c (patch)
tree0942444e882e0f6db2aee1092150bcdb75448b85
parent50cdaed5a36f7112c2ff01504c475457f0d4944e (diff)
make SetCellStyle quicker by skipping conversions in checkCellInArea, and skipping area checks when we are sure the cell can't be before or past the current row/col
Signed-off-by: Matthieu Bresson
-rw-r--r--cell.go25
-rw-r--r--cell_test.go40
-rw-r--r--lib.go41
-rw-r--r--lib_test.go59
-rw-r--r--styles.go12
5 files changed, 159 insertions, 18 deletions
diff --git a/cell.go b/cell.go
index 5d26338..bb363aa 100644
--- a/cell.go
+++ b/cell.go
@@ -455,27 +455,16 @@ func (f *File) SetCellDefault(sheet, axis, value string) {
// checkCellInArea provides function to determine if a given coordinate is
// within an area.
func checkCellInArea(cell, area string) bool {
- result := false
cell = strings.ToUpper(cell)
- col := string(strings.Map(letterOnlyMapF, cell))
- row, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
- xAxis := row - 1
- yAxis := TitleToNumber(col)
+ area = strings.ToUpper(area)
ref := strings.Split(area, ":")
- hCol := string(strings.Map(letterOnlyMapF, ref[0]))
- hRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, ref[0]))
- hyAxis := hRow - 1
- hxAxis := TitleToNumber(hCol)
+ from := ref[0]
+ to := ref[1]
- vCol := string(strings.Map(letterOnlyMapF, ref[1]))
- vRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, ref[1]))
- vyAxis := vRow - 1
- vxAxis := TitleToNumber(vCol)
-
- if hxAxis <= yAxis && yAxis <= vxAxis && hyAxis <= xAxis && xAxis <= vyAxis {
- result = true
- }
+ col, row := getCellColRow(cell)
+ fromCol, fromRow := getCellColRow(from)
+ toCol, toRow := getCellColRow(to)
- return result
+ return axisLowerOrEqualThan(fromCol, col) && axisLowerOrEqualThan(col, toCol) && axisLowerOrEqualThan(fromRow, row) && axisLowerOrEqualThan(row, toRow)
}
diff --git a/cell_test.go b/cell_test.go
new file mode 100644
index 0000000..2ab5413
--- /dev/null
+++ b/cell_test.go
@@ -0,0 +1,40 @@
+package excelize
+
+import "testing"
+
+func TestCheckCellInArea(t *testing.T) {
+ expectedTrueCellInAreaList := [][2]string{
+ [2]string{"c2", "A1:AAZ32"},
+ [2]string{"AA0", "Z0:AB1"},
+ [2]string{"B9", "A1:B9"},
+ [2]string{"C2", "C2:C2"},
+ }
+
+ for _, expectedTrueCellInArea := range expectedTrueCellInAreaList {
+ cell := expectedTrueCellInArea[0]
+ area := expectedTrueCellInArea[1]
+
+ cellInArea := checkCellInArea(cell, area)
+
+ if !cellInArea {
+ t.Fatalf("Expected cell %v to be in area %v, got false\n", cell, area)
+ }
+ }
+
+ expectedFalseCellInAreaList := [][2]string{
+ [2]string{"c2", "A4:AAZ32"},
+ [2]string{"C4", "D6:A1"}, // weird case, but you never know
+ [2]string{"AEF42", "BZ40:AEF41"},
+ }
+
+ for _, expectedFalseCellInArea := range expectedFalseCellInAreaList {
+ cell := expectedFalseCellInArea[0]
+ area := expectedFalseCellInArea[1]
+
+ cellInArea := checkCellInArea(cell, area)
+
+ if cellInArea {
+ t.Fatalf("Expected cell %v not to be inside of area %v, but got true\n", cell, area)
+ }
+ }
+}
diff --git a/lib.go b/lib.go
index 2f3df35..c0426d6 100644
--- a/lib.go
+++ b/lib.go
@@ -7,6 +7,7 @@ import (
"io"
"log"
"math"
+ "unicode"
)
// ReadZipReader can be used to read an XLSX in memory without touching the
@@ -132,3 +133,43 @@ func defaultTrue(b *bool) bool {
}
return *b
}
+
+// axisLowerOrEqualThan returns true if axis1 <= axis2
+// axis1/axis2 can be either a column or a row axis, e.g. "A", "AAE", "42", "1", etc.
+//
+// For instance, the following comparisons are all true:
+//
+// "A" <= "B"
+// "A" <= "AA"
+// "B" <= "AA"
+// "BC" <= "ABCD" (in a XLSX sheet, the BC col comes before the ABCD col)
+// "1" <= "2"
+// "2" <= "11" (in a XLSX sheet, the row 2 comes before the row 11)
+// and so on
+func axisLowerOrEqualThan(axis1, axis2 string) bool {
+ if len(axis1) < len(axis2) {
+ return true
+ } else if len(axis1) > len(axis2) {
+ return false
+ } else {
+ return axis1 <= axis2
+ }
+}
+
+// getCellColRow returns the two parts of a cell identifier (its col and row) as strings
+//
+// For instance:
+//
+// "C220" => "C", "220"
+// "aaef42" => "aaef", "42"
+// "" => "", ""
+func getCellColRow(cell string) (col, row string) {
+ for index, rune := range cell {
+ if unicode.IsDigit(rune) {
+ return cell[:index], cell[index:]
+ }
+
+ }
+
+ return cell, ""
+}
diff --git a/lib_test.go b/lib_test.go
new file mode 100644
index 0000000..3a4dc2c
--- /dev/null
+++ b/lib_test.go
@@ -0,0 +1,59 @@
+package excelize
+
+import "testing"
+
+func TestAxisLowerOrEqualThan(t *testing.T) {
+ trueExpectedInputList := [][2]string{
+ [2]string{"A", "B"},
+ [2]string{"A", "AA"},
+ [2]string{"B", "AA"},
+ [2]string{"BC", "ABCD"},
+ [2]string{"1", "2"},
+ [2]string{"2", "11"},
+ }
+
+ for _, trueExpectedInput := range trueExpectedInputList {
+ isLowerOrEqual := axisLowerOrEqualThan(trueExpectedInput[0], trueExpectedInput[1])
+ if !isLowerOrEqual {
+ t.Fatalf("Expected %v <= %v = true, got false\n", trueExpectedInput[0], trueExpectedInput[1])
+ }
+ }
+
+ falseExpectedInputList := [][2]string{
+ [2]string{"B", "A"},
+ [2]string{"AA", "A"},
+ [2]string{"AA", "B"},
+ [2]string{"ABCD", "AB"},
+ [2]string{"2", "1"},
+ [2]string{"11", "2"},
+ }
+
+ for _, falseExpectedInput := range falseExpectedInputList {
+ isLowerOrEqual := axisLowerOrEqualThan(falseExpectedInput[0], falseExpectedInput[1])
+ if isLowerOrEqual {
+ t.Fatalf("Expected %v <= %v = false, got true\n", falseExpectedInput[0], falseExpectedInput[1])
+ }
+ }
+}
+
+func TestGetCellColRow(t *testing.T) {
+ cellExpectedColRowList := map[string][2]string{
+ "C220": [2]string{"C", "220"},
+ "aaef42": [2]string{"aaef", "42"},
+ "bonjour": [2]string{"bonjour", ""},
+ "59": [2]string{"", "59"},
+ "": [2]string{"", ""},
+ }
+
+ for cell, expectedColRow := range cellExpectedColRowList {
+ col, row := getCellColRow(cell)
+
+ if col != expectedColRow[0] {
+ t.Fatalf("Expected cell %v to return col %v, got col %v\n", cell, expectedColRow[0], col)
+ }
+
+ if row != expectedColRow[1] {
+ t.Fatalf("Expected cell %v to return row %v, got row %v\n", cell, expectedColRow[1], row)
+ }
+ }
+}
diff --git a/styles.go b/styles.go
index 87bca13..8cee5ff 100644
--- a/styles.go
+++ b/styles.go
@@ -2327,7 +2327,19 @@ func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) {
completeCol(xlsx, vyAxis+1, vxAxis+1)
for r, row := range xlsx.SheetData.Row {
+ if r < hyAxis {
+ continue
+ } else if r > vyAxis {
+ break
+ }
+
for k, c := range row.C {
+ if k < hxAxis {
+ continue
+ } else if k > vxAxis {
+ break
+ }
+
if checkCellInArea(c.R, hcell+":"+vcell) {
xlsx.SheetData.Row[r].C[k].S = styleID
}