因工作需要用到跨合并单元格获取数据,所以写了个NPOI扩展类。
主要方法如下:
1.判断指定行/列索引(单元格)是否为合并单元格。
2.获取指定列索引的实际含有数据的单元格。
3.返回指定行/列索引的上一个实际含有数据的行。
4.返回指定行/列索引的下一个实际含有数据的行。
5.返回指定行/列索引的上一个实际含有数据的单元格。
6.返回指定行/列索引的下一个实际含有数据的单元格。
1 namespace NPOI 2 { 3 /// <summary> 4 /// 表示单元格的维度,通常用于表达合并单元格的维度 5 /// </summary> 6 public struct Dimension 7 { 8 /// <summary> 9 /// 含有数据的单元格(通常表示合并单元格的第一个跨度行第一个跨度列),该字段可能为null 10 /// </summary> 11 public ICell DataCell; 12 13 /// <summary> 14 /// 行跨度(跨越了多少行) 15 /// </summary> 16 public int RowSpan; 17 18 /// <summary> 19 /// 列跨度(跨越了多少列) 20 /// </summary> 21 public int ColumnSpan; 22 23 /// <summary> 24 /// 合并单元格的起始行索引 25 /// </summary> 26 public int FirstRowIndex; 27 28 /// <summary> 29 /// 合并单元格的结束行索引 30 /// </summary> 31 public int LastRowIndex; 32 33 /// <summary> 34 /// 合并单元格的起始列索引 35 /// </summary> 36 public int FirstColumnIndex; 37 38 /// <summary> 39 /// 合并单元格的结束列索引 40 /// </summary> 41 public int LastColumnIndex; 42 } 43 44 public static class ExcelExtension 45 { 46 /// <summary> 47 /// 判断指定行列所在的单元格是否为合并单元格,并且输出该单元格的维度 48 /// </summary> 49 /// <param name="sheet">Excel工作表</param> 50 /// <param name="rowIndex">行索引,从0开始</param> 51 /// <param name="columnIndex">列索引,从0开始</param> 52 /// <param name="dimension">单元格维度</param> 53 /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns> 54 public static bool IsMergeCell(this ISheet sheet, int rowIndex, int columnIndex, out Dimension dimension) 55 { 56 dimension = new Dimension 57 { 58 DataCell = null, 59 RowSpan = 1, 60 ColumnSpan = 1, 61 FirstRowIndex = rowIndex, 62 LastRowIndex = rowIndex, 63 FirstColumnIndex = columnIndex, 64 LastColumnIndex = columnIndex 65 }; 66 67 for (int i = 0; i < sheet.NumMergedRegions; i++) 68 { 69 CellRangeAddress range = sheet.GetMergedRegion(i); 70 sheet.IsMergedRegion(range); 71 72 //这种算法只有当指定行列索引刚好是合并单元格的第一个跨度行第一个跨度列时才能取得合并单元格的跨度 73 //if (range.FirstRow == rowIndex && range.FirstColumn == columnIndex) 74 //{ 75 // dimension.DataCell = sheet.GetRow(range.FirstRow).GetCell(range.FirstColumn); 76 // dimension.RowSpan = range.LastRow - range.FirstRow + 1; 77 // dimension.ColumnSpan = range.LastColumn - range.FirstColumn + 1; 78 // dimension.FirstRowIndex = range.FirstRow; 79 // dimension.LastRowIndex = range.LastRow; 80 // dimension.FirstColumnIndex = range.FirstColumn; 81 // dimension.LastColumnIndex = range.LastColumn; 82 // break; 83 //} 84 85 if ((rowIndex >= range.FirstRow && range.LastRow >= rowIndex) && (columnIndex >= range.FirstColumn && range.LastColumn >= columnIndex)) 86 { 87 dimension.DataCell = sheet.GetRow(range.FirstRow).GetCell(range.FirstColumn); 88 dimension.RowSpan = range.LastRow - range.FirstRow + 1; 89 dimension.ColumnSpan = range.LastColumn - range.FirstColumn + 1; 90 dimension.FirstRowIndex = range.FirstRow; 91 dimension.LastRowIndex = range.LastRow; 92 dimension.FirstColumnIndex = range.FirstColumn; 93 dimension.LastColumnIndex = range.LastColumn; 94 break; 95 } 96 } 97 98 bool result; 99 if (rowIndex >= 0 && sheet.LastRowNum > rowIndex) 100 { 101 IRow row = sheet.GetRow(rowIndex); 102 if (columnIndex >= 0 && row.LastCellNum > columnIndex) 103 { 104 ICell cell = row.GetCell(columnIndex); 105 result = cell.IsMergedCell; 106 107 if (dimension.DataCell == null) 108 { 109 dimension.DataCell = cell; 110 } 111 } 112 else 113 { 114 result = false; 115 } 116 } 117 else 118 { 119 result = false; 120 } 121 122 return result; 123 } 124 125 /// <summary> 126 /// 判断指定行列所在的单元格是否为合并单元格,并且输出该单元格的行列跨度 127 /// </summary> 128 /// <param name="sheet">Excel工作表</param> 129 /// <param name="rowIndex">行索引,从0开始</param> 130 /// <param name="columnIndex">列索引,从0开始</param> 131 /// <param name="rowSpan">行跨度,返回值最小为1,同时表示没有行合并</param> 132 /// <param name="columnSpan">列跨度,返回值最小为1,同时表示没有列合并</param> 133 /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns> 134 public static bool IsMergeCell(this ISheet sheet, int rowIndex, int columnIndex, out int rowSpan, out int columnSpan) 135 { 136 Dimension dimension; 137 bool result = sheet.IsMergeCell(rowIndex, columnIndex, out dimension); 138 139 rowSpan = dimension.RowSpan; 140 columnSpan = dimension.ColumnSpan; 141 142 return result; 143 } 144 145 /// <summary> 146 /// 判断指定单元格是否为合并单元格,并且输出该单元格的维度 147 /// </summary> 148 /// <param name="cell">单元格</param> 149 /// <param name="dimension">单元格维度</param> 150 /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns> 151 public static bool IsMergeCell(this ICell cell, out Dimension dimension) 152 { 153 return cell.Sheet.IsMergeCell(cell.RowIndex, cell.ColumnIndex, out dimension); 154 } 155 156 /// <summary> 157 /// 判断指定单元格是否为合并单元格,并且输出该单元格的行列跨度 158 /// </summary> 159 /// <param name="cell">单元格</param> 160 /// <param name="rowSpan">行跨度,返回值最小为1,同时表示没有行合并</param> 161 /// <param name="columnSpan">列跨度,返回值最小为1,同时表示没有列合并</param> 162 /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns> 163 public static bool IsMergeCell(this ICell cell, out int rowSpan, out int columnSpan) 164 { 165 return cell.Sheet.IsMergeCell(cell.RowIndex, cell.ColumnIndex, out rowSpan, out columnSpan); 166 } 167 168 /// <summary> 169 /// 返回上一个跨度行,如果rowIndex为第一行,则返回null 170 /// </summary> 171 /// <param name="sheet">Excel工作表</param> 172 /// <param name="rowIndex">行索引,从0开始</param> 173 /// <param name="columnIndex">列索引,从0开始</param> 174 /// <returns>返回上一个跨度行</returns> 175 public static IRow PrevSpanRow(this ISheet sheet, int rowIndex, int columnIndex) 176 { 177 return sheet.FuncSheet(rowIndex, columnIndex, (currentDimension, isMerge) => 178 { 179 //上一个单元格维度 180 Dimension prevDimension; 181 sheet.IsMergeCell(currentDimension.FirstRowIndex - 1, columnIndex, out prevDimension); 182 return prevDimension.DataCell.Row; 183 }); 184 } 185 186 /// <summary> 187 /// 返回下一个跨度行,如果rowIndex为最后一行,则返回null 188 /// </summary> 189 /// <param name="sheet">Excel工作表</param> 190 /// <param name="rowIndex">行索引,从0开始</param> 191 /// <param name="columnIndex">列索引,从0开始</param> 192 /// <returns>返回下一个跨度行</returns> 193 public static IRow NextSpanRow(this ISheet sheet, int rowIndex, int columnIndex) 194 { 195 return sheet.FuncSheet(rowIndex, columnIndex, (currentDimension, isMerge) => 196 isMerge ? sheet.GetRow(currentDimension.FirstRowIndex + currentDimension.RowSpan) : sheet.GetRow(rowIndex)); 197 } 198 199 /// <summary> 200 /// 返回上一个跨度行,如果row为第一行,则返回null 201 /// </summary> 202 /// <param name="row">行</param> 203 /// <returns>返回上一个跨度行</returns> 204 public static IRow PrevSpanRow(this IRow row) 205 { 206 return row.Sheet.PrevSpanRow(row.RowNum, row.FirstCellNum); 207 } 208 209 /// <summary> 210 /// 返回下一个跨度行,如果row为最后一行,则返回null 211 /// </summary> 212 /// <param name="row">行</param> 213 /// <returns>返回下一个跨度行</returns> 214 public static IRow NextSpanRow(this IRow row) 215 { 216 return row.Sheet.NextSpanRow(row.RowNum, row.FirstCellNum); 217 } 218 219 /// <summary> 220 /// 返回上一个跨度列,如果columnIndex为第一列,则返回null 221 /// </summary> 222 /// <param name="row">行</param> 223 /// <param name="columnIndex">列索引,从0开始</param> 224 /// <returns>返回上一个跨度列</returns> 225 public static ICell PrevSpanCell(this IRow row, int columnIndex) 226 { 227 return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) => 228 { 229 //上一个单元格维度 230 Dimension prevDimension; 231 row.Sheet.IsMergeCell(row.RowNum, currentDimension.FirstColumnIndex - 1, out prevDimension); 232 return prevDimension.DataCell; 233 }); 234 } 235 236 /// <summary> 237 /// 返回下一个跨度列,如果columnIndex为最后一列,则返回null 238 /// </summary> 239 /// <param name="row">行</param> 240 /// <param name="columnIndex">列索引,从0开始</param> 241 /// <returns>返回下一个跨度列</returns> 242 public static ICell NextSpanCell(this IRow row, int columnIndex) 243 { 244 return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) => 245 row.GetCell(currentDimension.FirstColumnIndex + currentDimension.ColumnSpan)); 246 } 247 248 /// <summary> 249 /// 返回上一个跨度列,如果cell为第一列,则返回null 250 /// </summary> 251 /// <param name="cell">单元格</param> 252 /// <returns>返回上一个跨度列</returns> 253 public static ICell PrevSpanCell(this ICell cell) 254 { 255 return cell.Row.PrevSpanCell(cell.ColumnIndex); 256 } 257 258 /// <summary> 259 /// 返回下一个跨度列,如果columnIndex为最后一列,则返回null 260 /// </summary> 261 /// <param name="cell">单元格</param> 262 /// <returns>返回下一个跨度列</returns> 263 public static ICell NextSpanCell(this ICell cell) 264 { 265 return cell.Row.NextSpanCell(cell.ColumnIndex); 266 } 267 268 /// <summary> 269 /// 返回指定行索引所在的合并单元格(区域)中的第一行(通常是含有数据的行) 270 /// </summary> 271 /// <param name="sheet">Excel工作表</param> 272 /// <param name="rowIndex">行索引,从0开始</param> 273 /// <returns>返回指定列索引所在的合并单元格(区域)中的第一行</returns> 274 public static IRow GetDataRow(this ISheet sheet, int rowIndex) 275 { 276 return sheet.FuncSheet(rowIndex, 0, (currentDimension, isMerge) => sheet.GetRow(currentDimension.FirstRowIndex)); 277 } 278 279 /// <summary> 280 /// 返回指定列索引所在的合并单元格(区域)中的第一行第一列(通常是含有数据的单元格) 281 /// </summary> 282 /// <param name="row">行</param> 283 /// <param name="columnIndex">列索引</param> 284 /// <returns>返回指定列索引所在的合并单元格(区域)中的第一行第一列</returns> 285 public static ICell GetDataCell(this IRow row, int columnIndex) 286 { 287 return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) => currentDimension.DataCell); 288 } 289 290 private static T FuncSheet<T>(this ISheet sheet, int rowIndex, int columnIndex, Func<Dimension, bool, T> func) 291 { 292 //当前单元格维度 293 Dimension currentDimension; 294 //是否为合并单元格 295 bool isMerge = sheet.IsMergeCell(rowIndex, columnIndex, out currentDimension); 296 297 return func(currentDimension, isMerge); 298 } 299 } 300 }