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合并单元格只有左上角的单元格会存储实际值,被合并覆盖的其余单元格读取时会返回空,取值必须取合并区域左上角的单元格。
针对你附图里的寄存器位定义场景(示例图如下):
你需要的三个字段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
相关产品推荐
相关产品推荐

