Apache POI在复制时更新公式引用

有没有办法在Apache POI中复制公式时更新公式引用?

用Excel表示你在第一行公式=A1/B1 。 如果您复制粘贴它,例如在第5行,公式变成=A5/B5.

在Apache POI中,如果您运行线路

 r5.getCell(2).setCellType(CellType.FORMULA); r5.getCell(2).setCellFormula(r1.getCell(2).getCellFormula()); 

公式保持=A1/B1

你的代码不是复制/粘贴东西,而是从一个单元格获取公式string,并将该公式string恰好设置为另一个单元格。 这不会更改公式string。 应该怎么办?

所以需要从一个单元格获取公式string,然后将此公式string调整到目标单元格。

由于apache poi能够评估公式,所以它也必须能够parsing公式。 parsing类位于包org.apache.poi.ss.formula和org.apache.poi.ss.formula.ptg中 。

所以我们可以使用这些类来调整公式string到目标单元格。

例:

Excel工作簿之后:

在这里输入图像说明

和下面的代码:

 import java.io.FileInputStream; import org.apache.poi.ss.formula.*; import org.apache.poi.ss.formula.ptg.*; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.*; import org.apache.poi.ss.util.CellAddress; public class ExcelCopyFormula { private static String copyFormula(XSSFSheet sheet, String formula, int coldiff, int rowdiff) { XSSFEvaluationWorkbook workbookWrapper = XSSFEvaluationWorkbook.create((XSSFWorkbook) sheet.getWorkbook()); Ptg[] ptgs = FormulaParser.parse(formula, workbookWrapper, FormulaType.CELL , sheet.getWorkbook().getSheetIndex(sheet)); for (int i = 0; i < ptgs.length; i++) { if (ptgs[i] instanceof RefPtgBase) { // base class for cell references RefPtgBase ref = (RefPtgBase) ptgs[i]; if (ref.isColRelative()) ref.setColumn(ref.getColumn() + coldiff); if (ref.isRowRelative()) ref.setRow(ref.getRow() + rowdiff); } else if (ptgs[i] instanceof AreaPtgBase) { // base class for range references AreaPtgBase ref = (AreaPtgBase) ptgs[i]; if (ref.isFirstColRelative()) ref.setFirstColumn(ref.getFirstColumn() + coldiff); if (ref.isLastColRelative()) ref.setLastColumn(ref.getLastColumn() + coldiff); if (ref.isFirstRowRelative()) ref.setFirstRow(ref.getFirstRow() + rowdiff); if (ref.isLastRowRelative()) ref.setLastRow(ref.getLastRow() + rowdiff); } } formula = FormulaRenderer.toFormulaString(workbookWrapper, ptgs); return formula; } public static void main(String[] args) throws Exception { XSSFWorkbook workbook = (XSSFWorkbook)WorkbookFactory.create(new FileInputStream("test.xlsx")); XSSFSheet sheet = workbook.getSheetAt(0); for (Row row : sheet) { for (Cell cell : row) { if (cell.getCellTypeEnum() == CellType.FORMULA) { CellAddress source = cell.getAddress(); String formula = cell.getCellFormula(); System.out.print(source + "=" + formula); int rowdiff = 3; int coldiff = -2; CellAddress target = new CellAddress(source.getRow() + rowdiff, source.getColumn() + coldiff); String newformula = copyFormula(sheet, formula, coldiff, rowdiff); System.out.println("->" + target + "=" + newformula); } } } workbook.close(); } } 

导致以下输出:

 E3=C3/D3->C6=A6/B6 E4=$C4/D$4->C7=$C7/B$4 E5=SUM(C3:D5)->C8=SUM(A6:B8) E6=SUM(C$3:$D6)->C9=SUM(A$3:$D9) E7=C3+SUM(C3:D7)->C10=A6+SUM(A6:B10) E8=C$3+SUM($C3:D$8)->C11=A$3+SUM($C6:B$8)