我正在使用POI 3.8来阅读excel我正在使用POI的用户模型api,它能够读取HSSF和XSSF两者但是在评估公式时存在一些问题POI 3.8不支持Excle的IFERROR功能是否有任何替代和我不希望将公式转换为ISERROR,因为旧版本的excel不支持它.
我知道POI 3.8不支持IFERROR,但我能做些什么来完成它 - 提前谢谢
os以下是线程"main"中的异常异常org.apache.poi.ss.formula.eval.NotImplementedException:在org.apache.poi.ss.formula.WorkbookEvaluator.addExceptionInfo(WorkbookEvaluator.java)评估单元Sheet1!F1时出错:356)在org.apache的org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:297)org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:229).位于TestFormula的TestFormula.cellValue(TestFormula.java:48)的org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.evaluate(XSSFFormulaEvaluator.java:117)中的poi.xssf.usermodel.XSSFFormulaEvaluator.evaluateFormulaCellValue(XSSFFormulaEvaluator.java:264) TestFormula.loadRows(TestFormula.java:22)的TestFormula.loadRows(TestFormula.java:29)中的.loadCell(TestFormula.java:37)位于FISValidator.main(FISValidator.java:27)引起:org.apache.poi .ss.formula.eval.NotImplementedException:IFERROR在org.apache.poi.ss.formula.atp.AnalysisToolPak $ NotImplemented.evaluate(AnalysisTool Pak.java:40)org.apache.poi.ss.formula.UserDefinedFunction.evaluate(UserDefinedFunction.java:64)atg.apache.poi.ss.formula.OperationEvaluatorFactory.evaluate(OperationEvaluatorFactory.java:129)at org .apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:491)at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:287)
编辑:我的答案已经过时,因为较新的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;
}
Run Code Online (Sandbox Code Playgroud)
更新:我已经将公式修改为更好!= D之前:它只会替换公式,如果它在字符串的开头,并且除了它之外没有任何其他公式或参数.After:现在它在整个字符串中搜索IFERROR的实例并替换它们ALL = D.