首页 > 其他分享 >NPOI扩展--判断指定单元格是否为合并单元格和输出该单元格的行列跨度(维度)

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

时间:2024-03-26 09:14:20浏览次数:27  
标签:int -- 单元格 NPOI columnIndex range dimension row

namespace NPOI
{
    /// <summary>
    /// 表示单元格的维度,通常用于表达合并单元格的维度
    /// </summary>
    public struct Dimension
    {
        /// <summary>
        /// 含有数据的单元格(通常表示合并单元格的第一个跨度行第一个跨度列),该字段可能为null
        /// </summary>
        public ICell DataCell;

        /// <summary>
        /// 行跨度(跨越了多少行)
        /// </summary>
        public int RowSpan;

        /// <summary>
        /// 列跨度(跨越了多少列)
        /// </summary>
        public int ColumnSpan;

        /// <summary>
        /// 合并单元格的起始行索引
        /// </summary>
        public int FirstRowIndex;

        /// <summary>
        /// 合并单元格的结束行索引
        /// </summary>
        public int LastRowIndex;

        /// <summary>
        /// 合并单元格的起始列索引
        /// </summary>
        public int FirstColumnIndex;

        /// <summary>
        /// 合并单元格的结束列索引
        /// </summary>
        public int LastColumnIndex;
    }

    public static class ExcelExtension
    {
        /// <summary>
        /// 判断指定行列所在的单元格是否为合并单元格,并且输出该单元格的维度
        /// </summary>
        /// <param name="sheet">Excel工作表</param>
        /// <param name="rowIndex">行索引,从0开始</param>
        /// <param name="columnIndex">列索引,从0开始</param>
        /// <param name="dimension">单元格维度</param>
        /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns>
        public static bool IsMergeCell(this ISheet sheet, int rowIndex, int columnIndex, out Dimension dimension)
        {
            dimension = new Dimension
            {
                DataCell = null,
                RowSpan = 1,
                ColumnSpan = 1,
                FirstRowIndex = rowIndex,
                LastRowIndex = rowIndex,
                FirstColumnIndex = columnIndex,
                LastColumnIndex = columnIndex
            };

            for (int i = 0; i < sheet.NumMergedRegions; i++)
            {
                CellRangeAddress range = sheet.GetMergedRegion(i);
                sheet.IsMergedRegion(range);

                //这种算法只有当指定行列索引刚好是合并单元格的第一个跨度行第一个跨度列时才能取得合并单元格的跨度
                //if (range.FirstRow == rowIndex && range.FirstColumn == columnIndex)
                //{
                //    dimension.DataCell = sheet.GetRow(range.FirstRow).GetCell(range.FirstColumn);
                //    dimension.RowSpan = range.LastRow - range.FirstRow + 1;
                //    dimension.ColumnSpan = range.LastColumn - range.FirstColumn + 1;
                //    dimension.FirstRowIndex = range.FirstRow;
                //    dimension.LastRowIndex = range.LastRow;
                //    dimension.FirstColumnIndex = range.FirstColumn;
                //    dimension.LastColumnIndex = range.LastColumn;
                //    break;
                //}

                if ((rowIndex >= range.FirstRow && range.LastRow >= rowIndex) && (columnIndex >= range.FirstColumn && range.LastColumn >= columnIndex))
                {
                    dimension.DataCell = sheet.GetRow(range.FirstRow).GetCell(range.FirstColumn);
                    dimension.RowSpan = range.LastRow - range.FirstRow + 1;
                    dimension.ColumnSpan = range.LastColumn - range.FirstColumn + 1;
                    dimension.FirstRowIndex = range.FirstRow;
                    dimension.LastRowIndex = range.LastRow;
                    dimension.FirstColumnIndex = range.FirstColumn;
                    dimension.LastColumnIndex = range.LastColumn;
                    break;
                }
            }

            bool result;
            if (rowIndex >= 0 && sheet.LastRowNum > rowIndex)
            {
                IRow row = sheet.GetRow(rowIndex);
                if (columnIndex >= 0 && row.LastCellNum > columnIndex)
                {
                    ICell cell = row.GetCell(columnIndex);
                    result = cell.IsMergedCell;

                    if (dimension.DataCell == null)
                    {
                        dimension.DataCell = cell;
                    }
                }
                else
                {
                    result = false;
                }
            }
            else
            {
                result = false;
            }

            return result;
        }

        /// <summary>
        /// 判断指定行列所在的单元格是否为合并单元格,并且输出该单元格的行列跨度
        /// </summary>
        /// <param name="sheet">Excel工作表</param>
        /// <param name="rowIndex">行索引,从0开始</param>
        /// <param name="columnIndex">列索引,从0开始</param>
        /// <param name="rowSpan">行跨度,返回值最小为1,同时表示没有行合并</param>
        /// <param name="columnSpan">列跨度,返回值最小为1,同时表示没有列合并</param>
        /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns>
        public static bool IsMergeCell(this ISheet sheet, int rowIndex, int columnIndex, out int rowSpan, out int columnSpan)
        {
            Dimension dimension;
            bool result = sheet.IsMergeCell(rowIndex, columnIndex, out dimension);

            rowSpan = dimension.RowSpan;
            columnSpan = dimension.ColumnSpan;

            return result;
        }

        /// <summary>
        /// 判断指定单元格是否为合并单元格,并且输出该单元格的维度
        /// </summary>
        /// <param name="cell">单元格</param>
        /// <param name="dimension">单元格维度</param>
        /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns>
        public static bool IsMergeCell(this ICell cell, out Dimension dimension)
        {
            return cell.Sheet.IsMergeCell(cell.RowIndex, cell.ColumnIndex, out dimension);
        }

        /// <summary>
        /// 判断指定单元格是否为合并单元格,并且输出该单元格的行列跨度
        /// </summary>
        /// <param name="cell">单元格</param>
        /// <param name="rowSpan">行跨度,返回值最小为1,同时表示没有行合并</param>
        /// <param name="columnSpan">列跨度,返回值最小为1,同时表示没有列合并</param>
        /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns>
        public static bool IsMergeCell(this ICell cell, out int rowSpan, out int columnSpan)
        {
            return cell.Sheet.IsMergeCell(cell.RowIndex, cell.ColumnIndex, out rowSpan, out columnSpan);
        }

        /// <summary>
        /// 返回上一个跨度行,如果rowIndex为第一行,则返回null
        /// </summary>
        /// <param name="sheet">Excel工作表</param>
        /// <param name="rowIndex">行索引,从0开始</param>
        /// <param name="columnIndex">列索引,从0开始</param>
        /// <returns>返回上一个跨度行</returns>
        public static IRow PrevSpanRow(this ISheet sheet, int rowIndex, int columnIndex)
        {
            return sheet.FuncSheet(rowIndex, columnIndex, (currentDimension, isMerge) =>
            {
                //上一个单元格维度
                Dimension prevDimension;
                sheet.IsMergeCell(currentDimension.FirstRowIndex - 1, columnIndex, out prevDimension);
                return prevDimension.DataCell.Row;
            });
        }

        /// <summary>
        /// 返回下一个跨度行,如果rowIndex为最后一行,则返回null
        /// </summary>
        /// <param name="sheet">Excel工作表</param>
        /// <param name="rowIndex">行索引,从0开始</param>
        /// <param name="columnIndex">列索引,从0开始</param>
        /// <returns>返回下一个跨度行</returns>
        public static IRow NextSpanRow(this ISheet sheet, int rowIndex, int columnIndex)
        {
            return sheet.FuncSheet(rowIndex, columnIndex, (currentDimension, isMerge) =>
                isMerge ? sheet.GetRow(currentDimension.FirstRowIndex + currentDimension.RowSpan) : sheet.GetRow(rowIndex));
        }

        /// <summary>
        /// 返回上一个跨度行,如果row为第一行,则返回null
        /// </summary>
        /// <param name="row">行</param>
        /// <returns>返回上一个跨度行</returns>
        public static IRow PrevSpanRow(this IRow row)
        {
            return row.Sheet.PrevSpanRow(row.RowNum, row.FirstCellNum);
        }

        /// <summary>
        /// 返回下一个跨度行,如果row为最后一行,则返回null
        /// </summary>
        /// <param name="row">行</param>
        /// <returns>返回下一个跨度行</returns>
        public static IRow NextSpanRow(this IRow row)
        {
            return row.Sheet.NextSpanRow(row.RowNum, row.FirstCellNum);
        }

        /// <summary>
        /// 返回上一个跨度列,如果columnIndex为第一列,则返回null
        /// </summary>
        /// <param name="row">行</param>
        /// <param name="columnIndex">列索引,从0开始</param>
        /// <returns>返回上一个跨度列</returns>
        public static ICell PrevSpanCell(this IRow row, int columnIndex)
        {
            return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) =>
            {
                //上一个单元格维度
                Dimension prevDimension;
                row.Sheet.IsMergeCell(row.RowNum, currentDimension.FirstColumnIndex - 1, out prevDimension);
                return prevDimension.DataCell;
            });
        }

        /// <summary>
        /// 返回下一个跨度列,如果columnIndex为最后一列,则返回null
        /// </summary>
        /// <param name="row">行</param>
        /// <param name="columnIndex">列索引,从0开始</param>
        /// <returns>返回下一个跨度列</returns>
        public static ICell NextSpanCell(this IRow row, int columnIndex)
        {
            return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) =>
                row.GetCell(currentDimension.FirstColumnIndex + currentDimension.ColumnSpan));
        }

        /// <summary>
        /// 返回上一个跨度列,如果cell为第一列,则返回null
        /// </summary>
        /// <param name="cell">单元格</param>
        /// <returns>返回上一个跨度列</returns>
        public static ICell PrevSpanCell(this ICell cell)
        {
            return cell.Row.PrevSpanCell(cell.ColumnIndex);
        }

        /// <summary>
        /// 返回下一个跨度列,如果columnIndex为最后一列,则返回null
        /// </summary>
        /// <param name="cell">单元格</param>
        /// <returns>返回下一个跨度列</returns>
        public static ICell NextSpanCell(this ICell cell)
        {
            return cell.Row.NextSpanCell(cell.ColumnIndex);
        }

        /// <summary>
        /// 返回指定行索引所在的合并单元格(区域)中的第一行(通常是含有数据的行)
        /// </summary>
        /// <param name="sheet">Excel工作表</param>
        /// <param name="rowIndex">行索引,从0开始</param>
        /// <returns>返回指定列索引所在的合并单元格(区域)中的第一行</returns>
        public static IRow GetDataRow(this ISheet sheet, int rowIndex)
        {
            return sheet.FuncSheet(rowIndex, 0, (currentDimension, isMerge) => sheet.GetRow(currentDimension.FirstRowIndex));
        }

        /// <summary>
        /// 返回指定列索引所在的合并单元格(区域)中的第一行第一列(通常是含有数据的单元格)
        /// </summary>
        /// <param name="row">行</param>
        /// <param name="columnIndex">列索引</param>
        /// <returns>返回指定列索引所在的合并单元格(区域)中的第一行第一列</returns>
        public static ICell GetDataCell(this IRow row, int columnIndex)
        {
            return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) => currentDimension.DataCell);
        }

        private static T FuncSheet<T>(this ISheet sheet, int rowIndex, int columnIndex, Func<Dimension, bool, T> func)
        {
            //当前单元格维度
            Dimension currentDimension;
            //是否为合并单元格
            bool isMerge = sheet.IsMergeCell(rowIndex, columnIndex, out currentDimension);

            return func(currentDimension, isMerge);
        }
    }
}

标签:int,--,单元格,NPOI,columnIndex,range,dimension,row
From: https://www.cnblogs.com/duixue/p/18095830

相关文章

  • 编辑距离算法
    1.题目给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数  。你可以对一个单词进行如下三种操作:删除一个字符替换一个字符插入一个字符示例:输入:word1="horse",word2="ros"输出:3解释:horse->rorse(将'h'替换为'r')ror......
  • 【插件更新日志】新发布的1.5.0版本插件中的增强模式,作用几何?
    近日,我们的插件迎来了自发布以来的首个大更新,发布了1.5.0版,更新了多个新特性,今天就带您来了解一下其中的【增强】模式。一、令人头疼的兼容性问题如上图所示,这是在MTK天玑7200-Ultra芯片下测试同一人体姿态识别的效果,未开启【增强】模式时,识别出的关键点错位严重,根本无法使......
  • blog-engine-06-pelican 静态网站生成 支持 markdown 和 reST 语法
    拓展阅读blog-engine-01-常见博客引擎jekyll/hugo/Hexo/Pelican/Gatsby/VuePress/Nuxt.js/Middleman对比blog-engine-02-通过博客引擎jekyll构建githubpages博客实战笔记blog-engine-02-博客引擎jekyll-jekyll博客引擎介绍blog-engine-02-博客引擎jekyll-jekyll如何......
  • 面试官:只知道v-model是:modelValue和@onUpdate语法糖,那你可以走了
    前言我们每天都在用v-model,并且大家都知道在vue3中v-model是:modelValue和@update:modelValue的语法糖。那你知道v-model指令是如何变成组件上的modelValue属性和@update:modelValue事件呢?将v-model指令转换为modelValue属性和@update:modelValue事件这一过程是在编译时还是运行......
  • C#虚方法和抽象方法
    usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespacetest0322{publicabstractclassTestAbstract//抽象方法只能在抽象类中定义;虚方法则不是{publicabstractvoidRun()......
  • 编码揭秘:解构字符%20背后的秘密与百分号编码艺术
    前言提到这个%20,想必大家都见过,熟悉一点编码的人,还会知道这玩意就是空格转换而来!那么我们一起破解,如何编码而来?我们今天继续学习前端编码知识,其他编码文章:前端Base64编码知识,一文打尽,探索起源,追求真相。localStorage灵魂五问。5M??10M!!!字母a的6种表示方法,以及其背后......
  • 再聊SPI机制
    前言去年更新了一系列和SPI相关的内容,最近因为业务需要,我又基于业务场景,实现了一版。对于什么是spi,很久之前有写过一篇文章,java之spi机制简介感兴趣的朋友可以蛮看一下需求分析用过原生jdk提供的spi的朋友,应该会知道原生jdk的spi有个缺陷,就是没法实现按需加载,因此本文的实现就......
  • 如何使用 JavaScript 导入和导出 Excel
    前言在现代的Web应用开发中,与Excel文件的导入和导出成为了一项常见而重要的任务。无论是数据交换、报告生成还是数据分析,与Excel文件的交互都扮演着至关重要的角色。本文小编将为大家介绍如何在熟悉的电子表格UI中轻松导入Excel文件,并以编程方式修改表格或允许用户进行编辑,最......
  • 【Cesium源码系列】Cesium的相机(1)
    Cesium相机内部保存着相机的基本信息,主要有以下几个属性:_transform:对外只读,变换矩阵_invTransform:对外只读,变换矩阵的逆_actualTransform:对内,实际变换矩阵_actualInvTransform:对内,实际变换矩阵的逆position:对外,相机的位置_position:对内,相机的位置_positionWC:对外只读,相机......
  • 属性遍历那些事儿:从入门到精通,笑谈间掌握技巧
    1.属性的分类普通属性原型属性不可枚举属性Symbol属性静态属性??我们先来看看下面这个对象。constsymbolIsAnimal=Symbol.for("pro_symbol_attr_isAnimal");constsymbolSay=Symbol.for("pro_symbol_method_say");constsymbolSalary=Symbol.for("ins_symbol_a......