PHPExcel插入数组公式

PHPExcel insert array formula

我要插入这个数组公式:

{=SUM(IF(FREQUENCY(IF(T9:T977=1,MATCH(U9:U977,U9:U977,0)),ROW(U9:U977)-ROW(U9)+1),1))}

但是当我使用时:

$sheet->getCell("C1")->setValue("{=SUM(IF(FREQUENCY(IF(T9:T977=1,MATCH(U9:U977,U9:U977,0)),ROW(U9:U977)-ROW(U9)+1),1))}");

不行,我查了文档,还是没找到。

我找不到任何答案,所以我通过 PHPExcel 为自己制定了一个解决方案:

in /PHPExcel/Cell.phpswitch($pDataType) 的第 251 行添加:

case PHPExcel_Cell_DataType::TYPE_FORMULA_ARRAY:
$this->_value = (string)$pValue;
break;

in /PHPExcel/Cell/DataType.php 添加这个常数:

const TYPE_FORMULA_ARRAY = 't';

最后 /PHPExcel/Writer/Excel2007/Worksheet.php我在第 1095 行开始的开关中添加了这个:

case 't':           // Array Formulae
    $objWriter->startElement('f');
    $objWriter->writeAttribute('t', 'array');
    $objWriter->writeAttribute('ref', $pCellAddress);
    $objWriter->writeAttribute('aca', '1');
    $objWriter->writeAttribute('ca', '1');
    $objWriter->text($cellValue);
    $objWriter->endElement();               
    if ($this->getParentWriter()->getOffice2003Compatibility() === false) {
        if ($this->getParentWriter()->getPreCalculateFormulas()) {
            $calculatedValue = $pCell->getCalculatedValue();
            if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) != '#') {
                $objWriter->writeElement('v', PHPExcel_Shared_String::FormatNumber($calculatedValue));
            } else {
                $objWriter->writeElement('v', '0');
            }
        } else {
            $objWriter->writeElement('v', '0');
    }
}
break;

然后我使用了这样的函数:

$sheet->getCell("C1")->setValueExplicit("=SUM(IF(FREQUENCY(IF(T9:T977=1,MATCH(U9:U977,U9:U977,0)),ROW(U9:U977)-ROW(U9)+1),1))", PHPExcel_Cell_DataType::TYPE_FORMULA_ARRAY);

当我创建 excel 文件时一切正常!

因为在搜索 PHPExcel 的后继者 PHPSpreadsheet 时仍然会出现这个 question/answer,我想补充一点,后者支持内置的数组公式。只需像往常一样分配公式并设置类型-数组的属性:

$attrs = $sheet->getCell("C1")->getFormulaAttributes();
$attrs['t'] = 'array';
$sheet->getCell("C1")->setFormulaAttributes($attrs);

这是我使用 PhpSpreadsheet 插入数组公式的修复方法。 我对功能做了一些改动 'writeCellFormula' (PhpSpreadsheet\Writer\Xlsx\Worksheet.php)

用法:

$sheet = $spreadsheet->getActiveSheet();
$attrs = $sheet->getCell("C1")->getFormulaAttributes();
$attrs['t'] = 'array';
$sheet->getCell("C1")->setFormulaAttributes($attrs);
$sheet->setCellValue("C1",'=SUM(A1:A3*B1:B3)');

预期输出: {=SUM(Q1:Q3*R1:R3) }

private function writeCellFormula(XMLWriter $objWriter, string $cellValue, Cell $pCell): void
{
    $attributes = $pCell->getFormulaAttributes();
    if ($attributes['t']=='array')
    {
        $pCellAddress = $pCell->getCoordinate();
        $objWriter->startElement('f');
        $objWriter->writeAttribute('t', 'array');
        $objWriter->writeAttribute('ref', $pCellAddress);
        //$objWriter->writeAttribute('aca', '1');
        //$objWriter->writeAttribute('ca', '1');
        $objWriter->text(substr($cellValue, 1));
        $objWriter->endElement();
        return;
    }
    
    $calculatedValue = $this->getParentWriter()->getPreCalculateFormulas() ? $pCell->getCalculatedValue() : $cellValue;
    if (is_string($calculatedValue)) {
        if (\PhpOffice\PhpSpreadsheet\Calculation\Functions::isError($calculatedValue)) {
            $this->writeCellError($objWriter, 'e', $cellValue, $calculatedValue);

            return;
        }
        $objWriter->writeAttribute('t', 'str');
    } 
    elseif (is_bool($calculatedValue) ) {
        $objWriter->writeAttribute('t', 'b');
        $calculatedValue = (int) $calculatedValue;
    }

    $objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue));
    self::writeElementIf(
        $objWriter,
        $this->getParentWriter()->getOffice2003Compatibility() === false,
        'v',
        ($this->getParentWriter()->getPreCalculateFormulas() && !is_array($calculatedValue) && substr($calculatedValue, 0, 1) !== '#')
            ? StringHelper::formatNumber($calculatedValue) : '0'
    );
}