2

我正在使用 POI 3.8 来读取 excel 我正在使用 POI 的用户模型 api,它能够同时读取 HSSF 和 XSSF 但是在评估公式 POI 3.8 不支持 Excle 的 IFERROR 函数时存在一些问题是否有任何替代方法,我不想将公式转换为 ISERROR,因为旧版本的 excel 不支持它。

我知道 POI 3.8 不支持 IFERROR 但我能做些什么来完成它 - 在此先感谢

以下是线程“主”org.apache.poi.ss.formula.eval.NotImplementedException 中的异常异常:在 org.apache.poi.ss.formula.WorkbookEvaluator.addExceptionInfo(WorkbookEvaluator.java 评估单元格 Sheet1!F1 时出错:356) 在 org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:229) 在 org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:297)。 poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateFormulaCellValue(XSSFFormulaEvaluator.java:264) at org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluate(XSSFFormulaEvaluator.java:117) at TestFormula.cellValue(TestFormula.java:48) at TestFormula .loadCell(TestFormula.java:37) 在 TestFormula.loadRows(TestFormula.java:29) 在 TestFormula.testRun(TestFormula.java:22) 在 FISValidator.main(FISValidator.java:27) 引起:org.apache.poi.ss.formula.eval.NotImplementedException: IFERROR at org.apache.poi.ss.formula.atp.AnalysisToolPak$NotImplemented.evaluate( AnalysisToolPak.java:40) 在 org.apache.poi.ss.formula.UserDefinedFunction.evaluate(UserDefinedFunction.java:64) 在 org.apache.poi.ss.formula.OperationEvaluatorFactory.evaluate(OperationEvaluatorFactory.java:129) 在 org .apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:491) 在 org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:287)UserDefinedFunction.evaluate(UserDefinedFunction.java:64) at org.apache.poi.ss.formula.OperationEvaluatorFactory.evaluate(OperationEvaluatorFactory.java:129) at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:第491章)在 org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAnyUserDefinedFunction.evaluate(UserDefinedFunction.java:64) at org.apache.poi.ss.formula.OperationEvaluatorFactory.evaluate(OperationEvaluatorFactory.java:129) at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:第491章)在 org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny

4

2 回答 2

6

编辑:由于较新的 Apache POI API 支持 IFERROR()


我最近也遇到了 IFERROR 的问题。所以我为此写了一个小技巧。希望这可以帮助:

请注意, IFERROR(value, value_if_error)IF(ISERROR(value), value_if_error, value)的作用相同

所以我在评估它们之前替换了这些公式。您需要做的就是调用replaceIfErrorFormulas()它将自动遍历整个工作表。

public static final int SIZE = "IFERROR(".length();   

private void replaceIfErrorFormulas(Sheet pSheet)
{
   for (Row row : pSheet)
   {
      for (Cell cell : row)
      {
         if ((cell != null) && 
             (cell.getCellType() == Cell.CELL_TYPE_FORMULA) &&
             (cell.getCellFormula().indexOf("IFERROR") != -1))
         {
            cell.setCellFormula(buildFormulaString(cell.getCellFormula()));
         }
      }
   }
}

private String buildFormulaString(String pFormula)
{
   if (pFormula.indexOf("IFERROR") == -1)
   {
      return pFormula;
   }

   String[] values = new String[2]; // will hold value, value_if_error
   char[] tokens = pFormula.toCharArray();
   int length = computeLength(pFormula); // length of IFERROR substring
   int iBegin = pFormula.indexOf("IFERROR");
   int iEnd = iBegin + length - 1;
   assert (iEnd < pFormula.length());      
   int iParam = 0;  // 0: value; 1: value_if_error
   int numPar = 0;  // number of parentheses

   // Split the parameters into VALUE and VALUE_IF_ERROR in values[]
   for (int i = iBegin; i < (length + iBegin) ; i++)
   {
      if (tokens[i] == '(')
      {
         values[iParam] += tokens[i];
         numPar++;
      }
      else if (tokens[i] == ')')
      {
         if (iParam < 1)
         {
            values[iParam] += tokens[i];
         }
         numPar--;
      }
      else if (Character.getType(tokens[i]) == Character.MATH_SYMBOL)
      {
         values[iParam] += tokens[i];
      }
      else if (tokens[i] == ',')
      {
         if (numPar > 1)
         {
            values[iParam] += tokens[i];
         }
         else
         {
            values[iParam++] += ')';
            numPar--;
         }
      }
      else
      {
         values[iParam] += tokens[i];
      }
      if (numPar < 0 && iParam == 1)
      {
         break;
      }
   }

   // Re-assign those parameters back to strings, removing the null character 
   String value        = values[0];
   String valueIfError = values[1];
   value        = value.substring(4 + SIZE - 1);
   valueIfError = valueIfError.substring(4);


   // Build new Formula that is equivalent to the old one.
   String newFormula = "IF(ISERROR(" + value + ")," 
                                     + valueIfError + ","
                                     + value +")";

   // Concatenate the untouched parts of the old formula to the new one      
   String left = pFormula.substring(0, iBegin);
   String right = pFormula.substring(iEnd + 1, pFormula.length());
   newFormula = left + newFormula + right;

   return buildFormulaString(newFormula);
}

// by checking the parentheses proceededing IFERROR, this method
// determines what is the size of the IFERROR substring
private int computeLength(String pFormula) 
{
   int length = SIZE;
   int numPar = 1; // Number of parentheses
   int iStart = pFormula.indexOf("IFERROR");
   char [] tokens = pFormula.toCharArray();

   for (int i = length + iStart; i < pFormula.length(); i++)
   {
      if (numPar == 0)
          break;
      if (tokens[i] == '(')
          numPar++;
      else if (tokens[i] == ')')
          numPar--;
      length++;
   }
   return length;
}

更新:我已将公式修改为更好!=D 之前:它只会替换位于字符串开头的公式,并且除了它之外没有任何其他公式或参数。之后:现在它在整个字符串中搜索 IFERROR 的实例并替换它们 ALL =D

于 2012-12-04T08:56:02.997 回答
6

IFERROR 现在已在 poi-3.10 中实现。因此,您无需破解即可升级到该版本。

于 2014-06-19T12:04:16.340 回答