POI / Excel:以“相对”方式应用公式

时间:2009-10-28 11:46:26

标签: java excel apache-poi poi-hssf

我正在使用Apache的POI来使用Java操作Excel(.xls)文件。

我正在尝试创建一个新的单元格,其内容是公式的结果,就像用户复制/粘贴公式一样(我称之为“相对”方式,与“绝对”相反)。

为了让自己更清楚,这是一个简单的例子: 单元格A1包含“1”,B1包含“2”,A2包含“3”,B2包含“4”。 单元格A3包含以下公式“= A1 + B1”。 如果我将公式复制到excel下的A4单元格,它将变为“= A2 + B2”:excel正在动态调整公式的内容。

不幸的是,我无法以编程方式获得相同的结果。我找到的唯一解决方案是将公式标记化并自己完成脏工作,但我真的怀疑这应该是这样做的。我无法在指南或API中找到我想要的内容。

有没有更简单的方法来解决这个问题?如果是这样的话,请指点我正确的方向吗?

致以最诚挚的问候,

尼尔斯

6 个答案:

答案 0 :(得分:9)

我也认为没有一种简单的方法可以做到这一点。

即使是POI网站上的HSSF and XSSD examples,例如TimesheetDemo手动执行公式构建。例如绕110线

String ref = (char)('A' + j) + "3:" + (char)('A' + j) + "12";
cell.setCellFormula("SUM(" + ref + ")");

答案 1 :(得分:7)

在我看来, user2622016 是正确的,除了他的解决方案只管理单元格引用,而不是区域引用(它不会例如,为=SUM(A1:B8)工作。

以下是我修复此问题的方法:

private void copyFormula(Sheet sheet, Cell org, Cell dest) {
    if (org == null || dest == null || sheet == null 
            || org.getCellType() != Cell.CELL_TYPE_FORMULA)
        return;
    if (org.isPartOfArrayFormulaGroup())
        return;
    String formula = org.getCellFormula();
    int shiftRows = dest.getRowIndex() - org.getRowIndex();
    int shiftCols = dest.getColumnIndex() - org.getColumnIndex();
    XSSFEvaluationWorkbook workbookWrapper = 
            XSSFEvaluationWorkbook.create((XSSFWorkbook) sheet.getWorkbook());
    Ptg[] ptgs = FormulaParser.parse(formula, workbookWrapper, FormulaType.CELL
            , sheet.getWorkbook().getSheetIndex(sheet));
    for (Ptg ptg : ptgs) {
        if (ptg instanceof RefPtgBase) // base class for cell references
        {
            RefPtgBase ref = (RefPtgBase) ptg;
            if (ref.isColRelative())
                ref.setColumn(ref.getColumn() + shiftCols);
            if (ref.isRowRelative())
                ref.setRow(ref.getRow() + shiftRows);
        } else if (ptg instanceof AreaPtg) // base class for range references
        {
            AreaPtg ref = (AreaPtg) ptg;
            if (ref.isFirstColRelative())
                ref.setFirstColumn(ref.getFirstColumn() + shiftCols);
            if (ref.isLastColRelative())
                ref.setLastColumn(ref.getLastColumn() + shiftCols);
            if (ref.isFirstRowRelative())
                ref.setFirstRow(ref.getFirstRow() + shiftRows);
            if (ref.isLastRowRelative())
                ref.setLastRow(ref.getLastRow() + shiftRows);
        }
    }
    formula = FormulaRenderer.toFormulaString(workbookWrapper, ptgs);
    dest.setCellFormula(formula);
}

我仍然不知道我的所有细胞配方是否正确,但它对我有用,快速可靠。

答案 2 :(得分:5)

我查看了 FormulaEvaluator 类,找到了一些可以为我们工作的POI内部类。

FormulaParser,它将String解析为“解析事物”数组:

String formula = cell.getCellFormula();
XSSFEvaluationWorkbook workbookWrapper = 
             XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);  
/* parse formula */
Ptg[] ptgs = FormulaParser.parse(formula, workbookWrapper, 
             FormulaType.CELL, 0 /*sheet index*/ );

ptgs现在是反向抛光表示法的公式。现在浏览所有元素并根据需要逐个修改引用:

/* re-calculate cell references */
for( Ptg ptg  : ptgs )
    if( ptg instanceof RefPtgBase )    //base class for cell reference "things"
    {
        RefPtgBase ref = (RefPtgBase)ptg;
        if( ref.isColRelative() )
            ref.setColumn( ref.getColumn() + 0 );
        if( ref.isRowRelative() )
            ref.setRow( ref.getRow() + 1 );
    }

你已经准备好将“解析事物”渲染回String:

formula = FormulaRenderer.toFormulaString(workbookWrapper, ptgs);
cell.setCellFormula( formula );

答案 3 :(得分:3)

相对复制公式的另一种方法,用poi 3.12进行测试

TRUE

根据需要更新共享公式:

$mark_sheets

从poi 3.12开始,SharedFormula不支持其他工作表中的单元格引用/公式(='Sheet1'!A1)。这是SharedFormula的更新:

public static void copyCellFormula(Workbook workbook, int sheetIndex, int rowIndex, int sourceColumnIndex, int destinationColumnIndex){
    XSSFEvaluationWorkbook formulaParsingWorkbook = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
    SharedFormula sharedFormula = new SharedFormula(SpreadsheetVersion.EXCEL2007);
    Sheet sheet = workbook.getSheetAt(sheetIndex);
    Row lookupRow = sheet.getRow(rowIndex);
    Cell sourceCell = lookupRow.getCell(sourceColumnIndex);
    Ptg[] sharedFormulaPtg = FormulaParser.parse(sourceCell.getCellFormula(), formulaParsingWorkbook, FormulaType.CELL, sheetIndex);
    Ptg[] convertedFormulaPtg = sharedFormula.convertSharedFormulas(sharedFormulaPtg, 0, 1);
    Cell destinationCell = lookupRow.createCell(destinationColumnIndex);
    destinationCell.setCellFormula(FormulaRenderer.toFormulaString(formulaParsingWorkbook, convertedFormulaPtg));
}

答案 4 :(得分:2)

我认为没有。 POI将不得不解析公式(考虑A1与$ A $ 1对比$ A1等)并且我不相信它具有该容量。当我过去这样做时,我总是不得不自己管理这个。对不起 - 不是你希望得到的答案!

答案 5 :(得分:-2)

你可以尝试一些第三方excel库,其中大多数可以处理相对/绝对范围公式。