You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OpenXML定位Excel前7列含文本的最后行(忽略格式)

修正OpenXML定位Excel前7列最后有效行的代码方案

需求明确:用OpenXML操作Excel,定位前7列(A-G列)的最后一行有效数据,仅检查单元格文本内容、忽略格式,且不能用Excel Interop;第8列及以后的单元格数据不影响判断,仅关注前7列是否有非空文本。

原代码的问题

  1. 列定位错误:原代码用row.Elements<Cell>().ElementAtOrDefault(i)取第i个单元格,但OpenXML中Row的Cell是按实际存在的单元格顺序存储的,并非严格按列索引排列(比如某行只有C列有值,ElementAt(0)是C列而非A列),导致无法准确检查A-G列。
  2. 未彻底忽略格式:原HasText函数未覆盖所有“有格式但无文本”的场景,比如部分格式化单元格可能存在空的CellValue或SharedStringItem。

修正后的代码

// 从最后一行倒序查找
foreach (var row in sheetData.Elements<Row>().Reverse())
{
    bool hasValidTextInFirst7Cols = row.Elements<Cell>()
        // 筛选前7列(A=1到G=7)
        .Where(cell => GetColumnIndex(cell) >= 1 && GetColumnIndex(cell) <=7)
        // 检查该单元格是否有非空文本
        .Any(cell => HasText(cell, workbookPart));

    if (hasValidTextInFirst7Cols)
    {
        lastRowIndex = row.RowIndex.Value;
        Console.WriteLine(lastRowIndex);
        break;
    }
}

// 辅助函数:获取单元格的列索引(将A/B/C...转换为1/2/3...)
private int GetColumnIndex(Cell cell)
{
    if (cell == null || string.IsNullOrEmpty(cell.CellReference))
        return 0;

    // 提取CellReference中的列部分(比如A1提取A,BC23提取BC)
    string columnReference = Regex.Replace(cell.CellReference, @"\d", "");
    int columnIndex = 0;
    foreach (char c in columnReference)
    {
        columnIndex = columnIndex * 26 + (c - 'A' + 1);
    }
    return columnIndex;
}

// 修正后的HasText:仅检查实际文本内容,忽略格式
private bool HasText(Cell cell, WorkbookPart workbookPart)
{
    if (cell == null)
        return false;

    // 先处理SharedString类型
    if (cell.DataType != null && cell.DataType.Value == CellValues.SharedString)
    {
        if (cell.CellValue == null || string.IsNullOrEmpty(cell.CellValue.InnerText))
            return false;

        if (!int.TryParse(cell.CellValue.InnerText, out int sharedStringIndex))
            return false;

        var sharedStringTable = workbookPart.SharedStringTablePart?.SharedStringTable;
        if (sharedStringTable == null || sharedStringIndex >= sharedStringTable.Elements<SharedStringItem>().Count())
            return false;

        SharedStringItem item = sharedStringTable.Elements<SharedStringItem>().ElementAt(sharedStringIndex);
        // 检查SharedStringItem的实际文本(忽略格式节点,只取纯文本)
        return !string.IsNullOrEmpty(item.InnerText.Trim());
    }

    // 处理普通文本/数值类型
    string cellText = cell.CellValue?.InnerText?.Trim();
    return !string.IsNullOrEmpty(cellText);
}

关键修正点

  1. 准确筛选前7列:通过GetColumnIndex函数解析CellReference获取真实列索引,确保只检查A-G列,不受单元格存储顺序影响。
  2. 彻底忽略格式:
    • HasText函数中对SharedString增加了空值校验,避免索引越界或空引用;
    • 对所有文本做Trim()处理,排除仅含空格的无效内容;
    • 忽略单元格的格式属性,仅判断实际文本是否非空。
  3. 高效判断行有效性:用Any()方法简化逻辑,只要前7列中有一个单元格有有效文本,就判定该行为最后有效行。

内容的提问来源于stack exchange,提问作者Róbert Fördős

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 19:07:31