【问题标题】:Apache POI Excel Formula entering @ Symbols where they don't belongApache POI Excel 公式输入不属于它们的@符号
【发布时间】:2020-06-27 18:45:09
【问题描述】:

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

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

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

data.getRow(r+1).getCell(c,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).setCellFormula(readings.get(r).getC(c));

其中数据是 XSSFSheet

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

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

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

谢谢

【问题讨论】:

    标签: java apache-poi


    【解决方案1】:

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

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

    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();
     }
    }
    

    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()))))";
    

    设置为公式,您正在使用Excel 365 打开生成的ExcelNew.xlsx,并且您尝试更改E2 中的公式,然后您会看到弹出窗口:

    为什么@操作符在这里?

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

    这里指的是Implicit intersection operator: @

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

    原因是新的AGGREGATE 函数通常在Excels 文件系统存储中以_xlfn. 为前缀。但是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()))))";
    

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

    【讨论】:

    • 谢谢!我对发生的事情一头雾水。第一个明显的变化是 @ 符号,我错过了 _xlfn 问题。我感激你。这是一个很好的答案,我希望它在未来对其他人有所帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-22
    • 1970-01-01
    • 2015-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多