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
This commit is contained in:
mbresson 2018-01-19 17:32:54 +08:00
parent 50cdaed5a3
commit 317ef65381
5 changed files with 159 additions and 18 deletions

25
cell.go
View File

@ -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)
col, row := getCellColRow(cell)
fromCol, fromRow := getCellColRow(from)
toCol, toRow := getCellColRow(to)
if hxAxis <= yAxis && yAxis <= vxAxis && hyAxis <= xAxis && xAxis <= vyAxis {
result = true
}
return result
return axisLowerOrEqualThan(fromCol, col) && axisLowerOrEqualThan(col, toCol) && axisLowerOrEqualThan(fromRow, row) && axisLowerOrEqualThan(row, toRow)
}

40
cell_test.go Normal file
View File

@ -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)
}
}
}

41
lib.go
View File

@ -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, ""
}

59
lib_test.go Normal file
View File

@ -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)
}
}
}

View File

@ -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
}