因工作需要用到跨合并单元格获取数据,所以写了个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 = ,
  60. ColumnSpan = ,
  61. FirstRowIndex = rowIndex,
  62. LastRowIndex = rowIndex,
  63. FirstColumnIndex = columnIndex,
  64. LastColumnIndex = columnIndex
  65. };
  66.  
  67. for (int i = ; 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 + ;
  89. dimension.ColumnSpan = range.LastColumn - range.FirstColumn + ;
  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 >= && sheet.LastRowNum > rowIndex)
  100. {
  101. IRow row = sheet.GetRow(rowIndex);
  102. if (columnIndex >= && 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 - , 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 - , 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, , (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. }

NPOI扩展--判断指定单元格是否为合并单元格和输出该单元格的行列跨度(维度)的更多相关文章

  1. 27.openpyxl 向指定单元格添加图片并修改图片大小 以及修改单元格行高列宽

    openpyxl 向指定单元格添加图片并修改图片大小 以及修改单元格行高列宽 from openpyxl import Workbook,load_workbook from openpyxl.dra ...

  2. 【EXCEL终极总结分享】基于NPOI扩展封装的简易操作工具类库(简单灵活易用,支持导出、导入、上传等常见操作)

    对于EXCEL的导入.导出,我之前已分享过多次,比如: 第一种方案:<我写的一个ExcelHelper通用类,可用于读取或生成数据>这个主要是利用把EXCEL当成一个DB来进行获取数据,导 ...

  3. asp.net将页面内容按需导入Excel,并设置excel样式,下载文件(解决打开格式与扩展名指定的格式不统一的问题)

    //请求一个excel类 Microsoft.Office.Interop.Excel.ApplicationClass excel = null; //创建 Workbook对象 Microsoft ...

  4. 个人永久性免费-Excel催化剂功能第52波-相同内容批量合并单元格,取消合并单元格并填充内容

    在高级Excel用户群体中无比痛恨的合并单元格,在现实的表格中却阴魂不散的纠缠不断.今天Excel催化剂也来成为“帮凶”,制造更多的合并单元格.虽然开发出此功能,请使用过程中务必要保持节制,在可以称为 ...

  5. javascript生成表格增删改查 JavaScript动态改变表格单元格内容 动态生成表格 JS获取表格任意单元格 javascript如何动态删除表格某一行

    jsp页面表格布局Html代码 <body onload="show()"> <center> <input type="text" ...

  6. C# 对Excel 单元格格式, 及行高、 列宽、 单元格边框线、 冻结设置

    一.对行高,列宽.单元格边框等的设置 这篇简短的文字对单元格的操作总结的比较全面,特此转载过来. private _Workbook _workBook = null; private Workshe ...

  7. String的两个API,判断指定字符串是否包含另一字符串,在字符串中删除指定字符串。

    // 在字符串中删除指定字符串. String phoneNum="1795112345"; phoneNum = phoneNum.replace("17951&quo ...

  8. 打开Excel时提示"您尝试打开的文件**.xls的格式与文件扩展名指定的格式不一致"

    问题描述:     系统安装了WPS时,Analyzer导出excel时候,会提示"您尝试打开的文件**.xls的格式与文件扩展名指定的格式不一致",这是Excel的安全问题,   ...

  9. Excel:您尝试打开的文件的格式与文件扩展名指定的格式不一致

    报错信息: 打开文件时提示"您尝试打开的文件xxx.xls的格式与文件扩展名指定的格式不一致.打开文件前请验证文件没有损坏且来源可信.是否立即打开该文件?",卸载Office 20 ...

随机推荐

  1. 数组&&函数数组

    数组:一次性定义多个同类型的变量,数组在 内存中存储空间必须是连续的(查询比较快)定义数组: int a[]; int[] a;分配空间: a=new int[5]; 自动为数组元素赋以默认值 a[0 ...

  2. 偶遇event.target

    今天在学习其他人代码的时候见到了event.target.nodeName,event.target.dataset.刚开始是一头雾水,便google一下.发现大多数给出的词条都是有关jQuery事件 ...

  3. E. Change-free

    Student Arseny likes to plan his life for n days ahead. He visits a canteen every day and he has alr ...

  4. ES6__异步开发优化

    一:JS事件循环 1:同步调用 同步调用是一种阻塞式调用,调用要等待双方执行完毕才返回,他是一种单向调用. 2:回调 回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口. 3: ...

  5. MVC,MVP,MVVM

    MVC模式: MVC即Model-VIew-Controller.他是1970年代被引入到软件设计大众的.MVC模式致力于关注点的切分,这意味着model和controller的逻辑是不与用户界面(V ...

  6. MongoDB分布式

    结构: ShardServer1:27020 ShardServer2:27021 ShardServer3:27022 ShardServer4:27023 ConfigServer:27100 R ...

  7. 每天一个Linux命令(12)--more命令

    more命令,功能类似cat,  cat 命令是这个文件的内容从上到下显示在屏幕上,more会以一页一页的显示方便使用者主页阅读,而最基本的指令就是按空格键就往下一页显示,按B键就会往回一页显示,而且 ...

  8. Struts2学习笔记②

    之前在跟着老师们做项目的时候经常会烦恼Struts.xml怎么配置,老师也没讲太清楚,都是说很简单,但是不懂的人就是太难了!哈哈,万事还是要靠自己的! struts.xml今天又看了几个小时的书,也跟 ...

  9. java关于map用来筛选的用法

    我有一个实体 PropTemplateItem{id,名称,父节点,模版id},父节点为root是定义为根节点. 例如数据: 001,颜色,root,123 002,白色,001,123 003,红色 ...

  10. subline text3常用插件介绍

    常用插件介绍:  html beautify(ctrl+shift+alt+f) 自动排版代码 Emmet 输入少量代码后摁Tab键,系统自动补全代码. AutoFileName 快速列出你想引用的文 ...