我正在使用Apache的POI来使用Java操作Excel(.xls)文件.
我正在尝试创建一个新的单元格,其内容是公式的结果,就像用户复制/粘贴公式一样(我称之为"相对"方式,与"绝对"相反).
为了使自己更清楚,这里有一个简单的例子:Cell A1包含"1",B1包含"2",A2包含"3",B2包含"4".单元格A3包含以下公式"= A1 + B1".如果我将公式复制到excel下的A4单元格,它将变为"= A2 + B2":excel正在动态调整公式的内容.
不幸的是,我无法以编程方式获得相同的结果.我找到的唯一解决方案是将公式标记化并自己完成脏工作,但我真的怀疑这应该是这样做的.我无法在指南或API中找到我想要的内容.
有没有更简单的方法来解决这个问题?如果是这样的话,请指点我正确的方向吗?
最好的祝福,
尼尔斯
我也认为没有一种简单的方法可以做到这一点.
甚至POI站点上的HSSF和XSSD示例(例如TimesheetDemo)也可以手动执行公式构建.例如,在110号线附近
String ref = (char)('A' + j) + "3:" + (char)('A' + j) + "12"; cell.setCellFormula("SUM(" + ref + ")");
在我看来,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); }
我仍然不知道我是否对所有细胞配方都正确,但它适用于我,快速可靠.
我查看了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 );