Apache POI Excel 公式输入不属于它们的@符号

Wad*_*lan 4 java apache-poi

我遇到了一个问题,我使用的公式非常具体。通过编程输入公式时,我得到了意想不到的结果。例如

MF = "IF(INDEX(CELL(\"width\",INDIRECT(ADDRESS(ROW(),COLUMN()))),1)<6,\"\",AGGREGATE(4,5,INDIRECT(ADDRESS(ROW()-"+readingsPerThirty+",COLUMN())):INDIRECT(ADDRESS(ROW()-1,COLUMN()))))";
Run Code Online (Sandbox Code Playgroud)

我将该 Excel 函数存储为字符串,稍后将被调用:

data.getRow(r+1).getCell(c,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).setCellFormula(readings.get(r).getC(c));
Run Code Online (Sandbox Code Playgroud)

其中数据是 XSSFSheet

当程序运行时,实际输入单元格的公式是:

=@IF(@INDEX(CELL("width",INDIRECT(ADDRESS(ROW(),COLUMN()))),1)<6,"",AGGREGATE(4,5,INDIRECT(ADDRESS(ROW()-1,COLUMN())):INDIRECT(ADDRESS(ROW()-1,COLUMN()))))
Run Code Online (Sandbox Code Playgroud)

我找不到任何关于@ 符号来自何处或导致它们的原因的文档或报告。我的问题是它们为什么会出现,我可以做些什么来防止它出现。@ 导致 Excel 出现错误,公式在没有它们的情况下也能正常工作。

谢谢

Axe*_*ter 6

问题在于Excel 365通常以_xlfnin为前缀的新函数Excel的文件系统存储。

让我们有一个完整的例子来重现这个问题:

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.ss.usermodel.*;

class ExcelSetCellFormula {
 
 static final String WRONG = "IF(INDEX(CELL(\"width\",INDIRECT(ADDRESS(ROW(),COLUMN()))),1)<6,\"\",AGGREGATE(4,5,INDIRECT(ADDRESS(ROW()-1,COLUMN())):INDIRECT(ADDRESS(ROW()-1,COLUMN()))))";

 static final String CORRECT = "IF(INDEX(CELL(\"width\",INDIRECT(ADDRESS(ROW(),COLUMN()))),1)<6,\"\",_xlfn.AGGREGATE(4,5,INDIRECT(ADDRESS(ROW()-1,COLUMN())):INDIRECT(ADDRESS(ROW()-1,COLUMN()))))";

 public static void main(String[] args) throws Exception {
  
  Workbook workbook = WorkbookFactory.create(new FileInputStream("./Excel.xlsx")); String filePath = "./ExcelNew.xlsx";
  Sheet data = workbook.getSheetAt(0);

  int r = 0;
  int c = 4;
  data.getRow(r+1).getCell(c,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).setCellFormula(WRONG);
  //data.getRow(r+1).getCell(c,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).setCellFormula(CORRECT);
  System.out.println(data.getRow(r+1).getCell(c));

  FileOutputStream out = new FileOutputStream(filePath);
  workbook.write(out);
  out.close() ;
  workbook.close();
 }
}
Run Code Online (Sandbox Code Playgroud)

Excel.xlsx需要具有具有的行的至少一个工作表1〜2已经。代码在单元格中设置公式E2

如果

static final String WRONG = "IF(INDEX(CELL(\"width\",INDIRECT(ADDRESS(ROW(),COLUMN()))),1)<6,\"\",AGGREGATE(4,5,INDIRECT(ADDRESS(ROW()-1,COLUMN())):INDIRECT(ADDRESS(ROW()-1,COLUMN()))))";
Run Code Online (Sandbox Code Playgroud)

被设置为公式,您正在打开结果ExcelNew.xlsxusingExcel 365并且您正在尝试更改 中的公式E2,然后您会看到弹出窗口:

为什么 @ 操作符在这里?

我们升级了 Excel 的公式语言,因此您可能会注意到某些公式中的 @ 运算符。您的公式的行为方式与以往相同。

这是指隐式交集运算符:@

但是如果我们仔细观察,之前在该公式中甚至没有理由使用该隐式交集运算符 IF。那么为什么要使用它呢?

原因是新AGGREGATE函数通常以_xlfn.in Excels 文件系统存储为前缀。但Apache POI不是这样做的。因此Excel 365,在渲染时将该函数解释为用户定义的函数,并为其添加前缀_xludf.. 这就是#NAME?错误的原因。这就是使用隐式交集运算符的原因@

因此,如果

static final String CORRECT = "IF(INDEX(CELL(\"width\",INDIRECT(ADDRESS(ROW(),COLUMN()))),1)<6,\"\",_xlfn.AGGREGATE(4,5,INDIRECT(ADDRESS(ROW()-1,COLUMN())):INDIRECT(ADDRESS(ROW()-1,COLUMN()))))";
Run Code Online (Sandbox Code Playgroud)

设置为公式,其中以AGGREGATE为前缀_xlfn.#NAME?错误消失。并且@不使用隐式交集运算符Excel 365

  • 谢谢你!我绞尽脑汁思考正在发生的事情。第一个明显的变化是 @ 符号,我错过了 _xlfn 问题。我感激你。这是一个很好的答案,我希望它能在未来帮助其他人! (2认同)