我正在使用Apache的POI来使用Java操作Excel(.xls)文件。
我正在尝试创建一个新的单元格,其内容是公式的结果,就像用户复制/粘贴公式一样(我称之为“相对”方式,与“绝对”相反)。
为了让自己更清楚,这是一个简单的例子: 单元格A1包含“1”,B1包含“2”,A2包含“3”,B2包含“4”。 单元格A3包含以下公式“= A1 + B1”。 如果我将公式复制到excel下的A4单元格,它将变为“= A2 + B2”:excel正在动态调整公式的内容。
不幸的是,我无法以编程方式获得相同的结果。我找到的唯一解决方案是将公式标记化并自己完成脏工作,但我真的怀疑这应该是这样做的。我无法在指南或API中找到我想要的内容。
有没有更简单的方法来解决这个问题?如果是这样的话,请指点我正确的方向吗?
致以最诚挚的问候,
尼尔斯
答案 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库,其中大多数可以处理相对/绝对范围公式。