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

时间:2017-12-01 13:15:06

标签: java excel excel-formula apache-poi

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

在Excel中,您在第1行中有公式=A1/B1。如果您将其复制粘贴(例如第5行),则公式将变为=A5/B5.

如果你运行行

,在Apache POI中
r5.getCell(2).setCellType(CellType.FORMULA);
r5.getCell(2).setCellFormula(r1.getCell(2).getCellFormula());

公式仍为=A1/B1

2 个答案:

答案 0 :(得分:4)

您的代码不是复制/粘贴某些内容,而是从一个单元格中获取公式字符串,并将此公式字符串精确地设置为另一个单元格。这不会改变公式字符串。它应该怎么做?

因此需要从一个单元格中获取公式字符串,然后将此公式字符串调整为目标单元格。

由于apache poi能够评估公式,因此它还必须能够解析公式。解析类位于包org.apache.poi.ss.formulaorg.apache.poi.ss.formula.ptg中。

因此我们可以使用这些类将公式字符串调整为目标单元格。

示例:

遵循Excel工作簿:

enter image description here

以下代码:

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)

答案 1 :(得分:0)

只要您想要NPOI的答案,我就通过@AxelRichter更新后的答案创建了C#版本:

public static string CopyFormula(ISheet sheet, string formula, int coldiff, int rowdiff)
{

    var workbook = sheet.Workbook;
    IFormulaParsingWorkbook evaluationWorkbook = null;
    if (sheet is XSSFWorkbook)
    {
        evaluationWorkbook = XSSFEvaluationWorkbook.Create(workbook);
    }
    else if (sheet is HSSFWorkbook)
    {
        evaluationWorkbook = HSSFEvaluationWorkbook.Create(workbook);
    }
    else if (sheet is SXSSFWorkbook)
    {
        evaluationWorkbook = SXSSFEvaluationWorkbook.Create((SXSSFWorkbook)workbook);
    }


    var ptgs = FormulaParser.Parse(formula, evaluationWorkbook,FormulaType.Cell, sheet.Workbook.GetSheetIndex(sheet));

    for (int i = 0; i < ptgs.Length; i++)
    {
        if (ptgs[i] is RefPtgBase) { 
            RefPtgBase ref2 = (RefPtgBase)ptgs[i];
            if (ref2.IsColRelative)
                ref2.Column = ref2.Column + coldiff;
            if (ref2.IsRowRelative)
                ref2.Row = ref2.Row + rowdiff;
        }
        else if (ptgs[i] is AreaPtgBase) { 
            AreaPtgBase ref2 = (AreaPtgBase)ptgs[i];
            if (ref2.IsFirstColRelative)
                ref2.FirstColumn += coldiff;
            if (ref2.IsLastColRelative)
                ref2.LastColumn += coldiff;
            if (ref2.IsFirstRowRelative)
                ref2.FirstRow += rowdiff;
            if (ref2.IsLastRowRelative)
                ref2.LastRow += rowdiff;
        }
    }

    formula = FormulaRenderer.ToFormulaString((IFormulaRenderingWorkbook)evaluationWorkbook, ptgs);
    return formula;
}