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

Perl解析Excel时如何获取合并单元格的大小与位置信息

用Perl解析Excel合并单元格直接用成熟的CPAN模块即可,不需要自己解析文件格式,核心操作非常直接:

前置依赖

根据你处理的Excel格式安装对应模块:

  • 处理.xls格式:安装Spreadsheet::ParseExcel
  • 处理.xlsx格式:安装Spreadsheet::ParseXLSX
    两个模块API完全兼容,切换只需要改模块引用即可。

核心实现逻辑

所有合并单元格的范围可以直接通过工作表对象的get_merged_areas()方法获取,返回值是数组引用,每个元素是一个四元组[$start_row, $start_col, $end_row, $end_col],对应合并区域的起始行、起始列、结束行、结束列,索引均从0开始计数。

注意:Excel合并单元格只有左上角的单元格会存储实际值,被合并覆盖的其余单元格读取时会返回空,取值必须取合并区域左上角的单元格。

针对你附图里的寄存器位定义场景(示例图如下):
My Excel example image
你需要的三个字段rsvd、frame_kind、destination都属于同一行内的横向合并单元格,直接遍历合并区域映射成位域结构即可,可直接运行的参考代码如下:

use strict;
use warnings;
use feature 'say';
# 处理xlsx替换为:use Spreadsheet::ParseXLSX;
use Spreadsheet::ParseExcel;

my $parser = Spreadsheet::ParseExcel->new();
my $wb = $parser->parse('your_reg_def.xls');
die $parser->error() unless $wb;
# 选择目标工作表,也可以按名称调用$wb->worksheet('SheetName')
my $ws = $wb->worksheet(0);
# 获取所有合并区域
my $merged_list = $ws->get_merged_areas();

my %field_info;
# 指定位定义所在的行索引,从0开始计数,根据你的实际表格修改
my $bit_row = 1;
# 总位宽,示例是32位寄存器
my $total_bit = 32;

for my $range (@$merged_list) {
    my ($s_r, $s_c, $e_r, $e_c) = @$range;
    # 跳过不在目标行的纵向/其他行合并区域
    next unless $s_r == $bit_row && $e_r == $bit_row;
    # 取合并单元格的值(仅左上角有值)
    my $cell = $ws->get_cell($s_r, $s_c);
    next unless $cell;
    my $name = $cell->value();
    # 适配示例里左高右低的位排布:最左侧列对应最高位31,最右侧列对应最低位0
    my $bit_high = $total_bit - 1 - $s_c;
    my $bit_low = $total_bit - 1 - $e_c;
    $field_info{$name} = {
        high  => $bit_high,
        low   => $bit_low,
        width => $bit_high - $bit_low + 1
    };
}

# 输出验证,和你需要的结果一致
for my $name (qw/rsvd frame_kind destination/) {
    my $f = $field_info{$name};
    say "$name: 合并范围$f->{low}至$f->{high},尺寸为$f->{width}";
}

运行后输出结果和你的预期完全匹配:

rsvd: 合并范围16至31,尺寸为16
frame_kind: 合并范围14至15,尺寸为2
destination: 合并范围0至13,尺寸为14

间隔单元格位置计算

要计算和指定位置间隔若干个合并单元格的目标位置,只需要把同组的合并字段按位序排序存为有序数组,直接按索引偏移取值即可:

# 把所有字段按bit位从低到高排序
my @sorted_field = sort { $a->{low} <=> $b->{low} } values %field_info;

# 示例:找最低位destination(索引0)间隔1个合并单元格的目标
# 相邻下一个(间隔0个)取索引+1,间隔N个取索引+N+1
my $gap = 1;
my $target_idx = 0 + $gap + 1;
my $target_field = $sorted_field[$target_idx];

如果你的表格是纵向合并的位定义,只需要把行列的计算逻辑互换即可,核心的合并区域获取方法通用。


内容的提问来源于stack exchange,提问作者Monica

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:12:19