Kaynağa Gözat

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

mbresson 7 yıl önce
ebeveyn
işleme
317ef65381
5 değiştirilmiş dosya ile 159 ekleme ve 18 silme
  1. 7 18
      cell.go
  2. 40 0
      cell_test.go
  3. 41 0
      lib.go
  4. 59 0
      lib_test.go
  5. 12 0
      styles.go

+ 7 - 18
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)
 }

+ 40 - 0
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)
+		}
+	}
+}

+ 41 - 0
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, ""
+}

+ 59 - 0
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)
+		}
+	}
+}

+ 12 - 0
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
 			}