在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
。
答案 0 :(得分:4)
您的代码不是复制/粘贴某些内容,而是从一个单元格中获取公式字符串,并将此公式字符串精确地设置为另一个单元格。这不会改变公式字符串。它应该怎么做?
因此需要从一个单元格中获取公式字符串,然后将此公式字符串调整为目标单元格。
由于apache poi
能够评估公式,因此它还必须能够解析公式。解析类位于包org.apache.poi.ss.formula和org.apache.poi.ss.formula.ptg中。
因此我们可以使用这些类将公式字符串调整为目标单元格。
示例:
遵循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)
答案 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;
}