merge.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to
  6. // and read from XLSX files. Support reads and writes XLSX file generated by
  7. // Microsoft Excel™ 2007 and later. Support save file without losing original
  8. // charts of XLSX. This library needs Go version 1.10 or later.
  9. package excelize
  10. import (
  11. "fmt"
  12. "strings"
  13. )
  14. // MergeCell provides a function to merge cells by given coordinate area and
  15. // sheet name. For example create a merged cell of D3:E9 on Sheet1:
  16. //
  17. // err := f.MergeCell("Sheet1", "D3", "E9")
  18. //
  19. // If you create a merged cell that overlaps with another existing merged cell,
  20. // those merged cells that already exist will be removed.
  21. //
  22. // B1(x1,y1) D1(x2,y1)
  23. // +------------------------+
  24. // | |
  25. // A4(x3,y3) | C4(x4,y3) |
  26. // +------------------------+ |
  27. // | | | |
  28. // | |B5(x1,y2) | D5(x2,y2)|
  29. // | +------------------------+
  30. // | |
  31. // |A8(x3,y4) C8(x4,y4)|
  32. // +------------------------+
  33. //
  34. func (f *File) MergeCell(sheet, hcell, vcell string) error {
  35. rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)
  36. if err != nil {
  37. return err
  38. }
  39. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  40. _ = sortCoordinates(rect1)
  41. hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
  42. vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
  43. xlsx, err := f.workSheetReader(sheet)
  44. if err != nil {
  45. return err
  46. }
  47. ref := hcell + ":" + vcell
  48. if xlsx.MergeCells != nil {
  49. for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
  50. cellData := xlsx.MergeCells.Cells[i]
  51. if cellData == nil {
  52. continue
  53. }
  54. cc := strings.Split(cellData.Ref, ":")
  55. if len(cc) != 2 {
  56. return fmt.Errorf("invalid area %q", cellData.Ref)
  57. }
  58. rect2, err := f.areaRefToCoordinates(cellData.Ref)
  59. if err != nil {
  60. return err
  61. }
  62. // Delete the merged cells of the overlapping area.
  63. if isOverlap(rect1, rect2) {
  64. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
  65. i--
  66. if rect1[0] > rect2[0] {
  67. rect1[0], rect2[0] = rect2[0], rect1[0]
  68. }
  69. if rect1[2] < rect2[2] {
  70. rect1[2], rect2[2] = rect2[2], rect1[2]
  71. }
  72. if rect1[1] > rect2[1] {
  73. rect1[1], rect2[1] = rect2[1], rect1[1]
  74. }
  75. if rect1[3] < rect2[3] {
  76. rect1[3], rect2[3] = rect2[3], rect1[3]
  77. }
  78. hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
  79. vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
  80. ref = hcell + ":" + vcell
  81. }
  82. }
  83. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &xlsxMergeCell{Ref: ref})
  84. } else {
  85. xlsx.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ref}}}
  86. }
  87. return err
  88. }
  89. // UnmergeCell provides a function to unmerge a given coordinate area.
  90. // For example unmerge area D3:E9 on Sheet1:
  91. //
  92. // err := f.UnmergeCell("Sheet1", "D3", "E9")
  93. //
  94. // Attention: overlapped areas will also be unmerged.
  95. func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
  96. xlsx, err := f.workSheetReader(sheet)
  97. if err != nil {
  98. return err
  99. }
  100. rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)
  101. if err != nil {
  102. return err
  103. }
  104. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  105. _ = sortCoordinates(rect1)
  106. // return nil since no MergeCells in the sheet
  107. if xlsx.MergeCells == nil {
  108. return nil
  109. }
  110. i := 0
  111. for _, cellData := range xlsx.MergeCells.Cells {
  112. if cellData == nil {
  113. continue
  114. }
  115. cc := strings.Split(cellData.Ref, ":")
  116. if len(cc) != 2 {
  117. return fmt.Errorf("invalid area %q", cellData.Ref)
  118. }
  119. rect2, err := f.areaRefToCoordinates(cellData.Ref)
  120. if err != nil {
  121. return err
  122. }
  123. if isOverlap(rect1, rect2) {
  124. continue
  125. }
  126. xlsx.MergeCells.Cells[i] = cellData
  127. i++
  128. }
  129. xlsx.MergeCells.Cells = xlsx.MergeCells.Cells[:i]
  130. return nil
  131. }
  132. // GetMergeCells provides a function to get all merged cells from a worksheet
  133. // currently.
  134. func (f *File) GetMergeCells(sheet string) ([]MergeCell, error) {
  135. var mergeCells []MergeCell
  136. xlsx, err := f.workSheetReader(sheet)
  137. if err != nil {
  138. return mergeCells, err
  139. }
  140. if xlsx.MergeCells != nil {
  141. mergeCells = make([]MergeCell, 0, len(xlsx.MergeCells.Cells))
  142. for i := range xlsx.MergeCells.Cells {
  143. ref := xlsx.MergeCells.Cells[i].Ref
  144. axis := strings.Split(ref, ":")[0]
  145. val, _ := f.GetCellValue(sheet, axis)
  146. mergeCells = append(mergeCells, []string{ref, val})
  147. }
  148. }
  149. return mergeCells, err
  150. }
  151. // MergeCell define a merged cell data.
  152. // It consists of the following structure.
  153. // example: []string{"D4:E10", "cell value"}
  154. type MergeCell []string
  155. // GetCellValue returns merged cell value.
  156. func (m *MergeCell) GetCellValue() string {
  157. return (*m)[1]
  158. }
  159. // GetStartAxis returns the merge start axis.
  160. // example: "C2"
  161. func (m *MergeCell) GetStartAxis() string {
  162. axis := strings.Split((*m)[0], ":")
  163. return axis[0]
  164. }
  165. // GetEndAxis returns the merge end axis.
  166. // example: "D4"
  167. func (m *MergeCell) GetEndAxis() string {
  168. axis := strings.Split((*m)[0], ":")
  169. return axis[1]
  170. }