繁体   English   中英

perl Excel::Writer::XLSX 将公式复制到一行的多个后续单元格

[英]perl Excel::Writer::XLSX copy formula to several subsequent cells of a row

在 EXCEL 你可以写一个公式,标记单元格并使用标记右下角的“+”将公式复制到同一行或列的后续单元格。 相对参考会自动调整。

有没有办法用 Excel::Writer::XLSX 来完成这个?

我已经编写了一个基本实现,它可以在下方和右侧处理单个单元格。 您可以使用它作为示例来了解如何做更复杂的事情。 它用$过滤掉固定单元格,因为它们不能递增。 它不适用于拉起或离开。

我添加了一个测试来解释 output 的样子。 解释如下。

use strict;
use warnings;
use feature 'say';

# caveat: does not check if the cells are inside of quotes!
sub pull_formula {
    my ($formula, $from, $to) = @_;

    my ($col_from, $row_from) = $from =~ m/([A-Z]+)([0-9]+)/;
    my ($col_to,   $row_to)   = $to   =~ m/([A-Z]+)([0-9]+)/;

    my @formulas;

    # determine direction, do we go down or right
    if ($col_from eq $col_to) {

        # pulling down, increment numbers
        foreach my $n (++$row_from .. $row_to) {
            $formula =~ s{
                ([A-Z]+)
                ([0-9]+)
            }{$1 . ($2+1)}gex;
            push @formulas, $formula;
        }
    }
    else {
        # pulling right, increment letters
        foreach my $n (++$col_from .. $col_to) {
            $formula =~ s{
                (?<!       \$)       # not preceded by a dollar
                (?<col>    [A-Z]+)   # column
                (?<dollar> \$?)      # optional dollar sign for row
                (?<row>    [0-9]+)   # row
            }{
                do { my $c = $+{col}; ++$c }
                    . $+{dollar}
                    . $+{row}
            }gex;
            push @formulas, $formula;
        }
    }

    return \@formulas;
}

use Test::More;

is_deeply pull_formula('=B5 + C5', 'A5', 'A8'), [
    '=B6 + C6',
    '=B7 + C7',
    '=B8 + C8',
];

is_deeply pull_formula('=MIN(B5:B$999)', 'A5', 'A8'), [
    '=MIN(B6:B$999)',
    '=MIN(B7:B$999)',
    '=MIN(B8:B$999)',
];

is_deeply pull_formula('=VLOOKUP(B3,B$2:E$7,2,FALSE)', 'B3', 'B5'), [
    '=VLOOKUP(B4,B$2:E$7,2,FALSE)',
    '=VLOOKUP(B5,B$2:E$7,2,FALSE)',
];

is_deeply pull_formula('=SUM(Y1:Y10)', 'Y11', 'AB11'), [
    '=SUM(Z1:Z10)',
    '=SUM(AA1:AA10)',
    '=SUM(AB1:AB10)',
];

done_testing;

这个想法是用公式调用 function,你想要填充的范围是两个 arguments。如果你可以访问工作表,你当然可以只用一个单元格参数来完成这一切,你还想添加多少填写。但这更容易。

我们首先将单元格分成 cols 和 rows,然后决定是否要增加数字(行)或字母(cols)。

数字更简单,因为我们可以对它们进行数学运算。 一般的想法是迭代公式,找到每个出现的单元格,并将其替换为下一个更高的单元格。 我们使用的正则表达式替换具有用于在模式中添加格式的/x标志、用于将替换视为 Perl 代码的/e标志以及用于全局执行此操作的/g标志,这意味着尽可能多地重复。

对于字母,模式更棘手。 我们不需要获取前面带有美元符号$的字母,因此在开始时有一个否定的回顾。 我使用命名捕获组 ( (?<name>pattern) ) 使捕获更易于阅读。 注意所有空格都被忽略,它来自/x修饰符。 对于字母,数字前面是否有美元并不重要,但我们必须捕获它。 如果没有美元, $+{dollar}将是一个空字符串。

Perl 以与 Excel 列相同的方式递增字母。 AAZ之后,这很方便。 但是 Perl 只对范围和增量运算符++执行此操作,我们不能将其应用于捕获变量,因此我们必须首先将其分配给一个新变量。 为了在替换内部执行此操作,我们使用了一个do块。

我已将所有模式放入一个数组中并返回一个引用,但是您当然可以直接写入工作表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM