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