英文:
Apache POI's FormulaEvaluator doesn't work after modifying a Cell's formula
问题
我正在使用Apache POI将一些测试用例的期望结果写入电子表格...
目前,这些期望结果都是以字符串单元格值的形式存在的。它们包含一些预期的金额...
这是一个示例行:
会员ID | NPI编号 | 会员前缀 | 会员名 | 会员姓 | 会员后缀 | 付款频率(A、M、S、Q) | 是否为子会员? | 预期费用 | 预期频率折扣 | 预期家庭折扣 | 预期净金额 | 预期总分期付款 | 预期净分期付款 | 测试用例步骤2通过? |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
139 | 1209360364 | Main07-28-2023 01:28:49 | RandomMember | A | true | $ 2,362.00 | $ 326.00 | $ 116.91 | $1,919.09 | $ 2,362.00 | $ 1,919.09 | true |
我确保金额以"会计数字格式"显示。
我注意到需要让Excel计算一个"预期净金额"(一个单元格减去其他一些单元格的总和),而不是通过我的代码计算,可以通过输入以下公式实现:
=I34-(J34+K34)
这在电子表格中可以正常工作:按下回车后,值会被计算出来。然而,当我尝试以编程方式读取它时,遇到了一些问题:
这个工具方法:
public static double GetDollarAmount(Cell cell) {
switch (cell.getCellType()) {
case CellType.NUMERIC.code:
return cell.getNumericCellValue();
case CellType.STRING.code:
return SMDNumberUtils.parseDouble(cell.getStringCellValue());
case CellType.FORMULA.code:
return cell.getSheet().getWorkbook()
.getCreationHelper()
.createFormulaEvaluator()
.evaluate(cell)
.getNumberValue();
default:
throw new IllegalStateException("Cell Type ${cell.getCellTypeEnum().name} not yet supported!")
}
}
对于公式类型的单元格失败了,因为它返回的是0,而不是在示例行中的1919.09。当我检查evaluate()
调用返回的CellValue
时,我看到一个带有#VALUE!
的CellValue
(通常在尝试在字符串值上使用数值公式时会抛出该异常)。
即使我尝试调整我的代码来重新编写公式,通过在任何单元格引用周围添加"VALUE()":
public static double GetDollarAmount(Cell cell) {
switch (cell.getCellType()) {
case CellType.NUMERIC.code:
return cell.getNumericCellValue();
case CellType.STRING.code:
return SMDNumberUtils.parseDouble(cell.getStringCellValue());
case CellType.FORMULA.code:
FormulaEvaluator evaluator = cell.getSheet().getWorkbook()
.getCreationHelper()
.createFormulaEvaluator();
CellValue cellValue = evaluator.evaluate(cell);
if (!cellValue.getCellTypeEnum().equals(CellType.ERROR))
return cellValue.getNumberValue();
cell.setCellFormula(cell.getCellFormula()
.replaceAll(/[A-Z]+\d+/, { match ->
return "VALUE($match)"
}))
return evaluator.evaluate(cell)
.getNumberValue();
default:
throw new IllegalStateException("Cell Type ${cell.getCellTypeEnum().name} not yet supported!")
}
}
它仍然失败,出现相同的问题!除了下一次运行时我们有一个安全的公式之外,没有任何变化!
在我的测试框架Katalon Studio上,如何解决这个问题,考虑到我被困在Apache POI v3.17上?
英文:
I am using Apache POI to write to a spreadsheet some test case expectations...
These expectations, as of right now, are all in the form of string cell values. They contain some expected dollar amounts...
Here's example row:
Member ID | NPI Number | Member Prefix | Member First Name | Member Last Name | Member Suffix | Payment Frequency (A, M, S, Q) | Is Child Member? | Expected Fee | Expected Frequency Discount | Expected Family Discount | Expected Net Amount | Expected Gross Installment | Expected Net Installment | Test Case Step 2 Passed? |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
139 | 1209360364 | Main07-28-2023 01:28:49 | RandomMember | A | true | $ 2,362.00 | $ 326.00 | $ 116.91 | $1,919.09 | $ 2,362.00 | $ 1,919.09 | true |
I make sure that the dollar amounts have the Accounting Number Format.
I did notice a need to have Excel calculate an Expected Net Amount (one cell minus the sum of some others), instead of my code, by entering in a formula like:
=I34-(J34+K34)
This works in the spreadsheet: after hitting enter, the value is calculated. However, when I try to read it programmatically, I face some issue:
The util method:
public static double GetDollarAmount(Cell cell) {
switch (cell.getCellType()) {
case CellType.NUMERIC.code:
return cell.getNumericCellValue();
case CellType.STRING.code:
return SMDNumberUtils.parseDouble(cell.getStringCellValue());
case CellType.FORMULA.code:
return cell.getSheet().getWorkbook()
.getCreationHelper()
.createFormulaEvaluator()
.evaluate(cell)
.getNumberValue();
default:
throw new IllegalStateException("Cell Type ${cell.getCellTypeEnum().name} not yet supported!")
}
}
fails for the formula-type cell, because it returns 0 instead of, in the case of that example row, 1919.09 . When I check the CellValue
that the evaluate()
call returns, I see a CellValue
with #VALUE!
(which typically gets thrown when you're tryna use a numeric formula on string values)
Even when I try to tweak my code to re-write the formula, by wrapping "VALUE()" around any cell references:
public static double GetDollarAmount(Cell cell) {
switch (cell.getCellType()) {
case CellType.NUMERIC.code:
return cell.getNumericCellValue();
case CellType.STRING.code:
return SMDNumberUtils.parseDouble(cell.getStringCellValue());
case CellType.FORMULA.code:
FormulaEvaluator evaluator = cell.getSheet().getWorkbook()
.getCreationHelper()
.createFormulaEvaluator();
CellValue cellValue = evaluator.evaluate(cell);
if (!cellValue.getCellTypeEnum().equals(CellType.ERROR))
return cellValue.getNumberValue();
cell.setCellFormula(cell.getCellFormula()
.replaceAll(/[A-Z]+\d+/, { match ->
return "VALUE($match)"
}))
return evaluator.evaluate(cell)
.getNumberValue();
default:
throw new IllegalStateException("Cell Type ${cell.getCellTypeEnum().name} not yet supported!")
}
}
It still fails, with the same issue! Nothing changes, except we have a safe formula for next run!
How can I fix this, given that my testing framework, Katalon Studio, has me stuck on Apache POI v3.17 ?
答案1
得分: 0
我能够修复这个问题,只需对代码进行一些调整:
public static double GetDollarAmount(Cell cell) {
switch (cell.getCellType()) {
case CellType.NUMERIC.code:
return cell.getNumericCellValue();
case CellType.STRING.code:
return SMDNumberUtils.parseDouble(cell.getStringCellValue());
case CellType.FORMULA.code:
CellValue cellValue = this.EvaluateCellFormula(cell);
if (!cellValue.getCellTypeEnum().equals(CellType.ERROR))
return cellValue.getNumberValue();
cell.setCellFormula(cell.getCellFormula()
.replaceAll(/[A-Z]+\d+/, { match ->
return "VALUE($match)"
}))
return this.EvaluateCellFormula(cell)
.getNumberValue();
default:
throw new IllegalStateException("Cell Type ${cell.getCellTypeEnum().name} not yet supported!")
}
}
public static CellValue EvaluateCellFormula(Cell cell) {
return cell.getSheet().getWorkbook()
.getCreationHelper()
.createFormulaEvaluator()
.evaluate(cell);
}
看起来我们每次调用evaluate()
时都需要一个新的FormulaEvaluator
...
英文:
I was able to fix this problem, with some tweaking of the code:
public static double GetDollarAmount(Cell cell) {
switch (cell.getCellType()) {
case CellType.NUMERIC.code:
return cell.getNumericCellValue();
case CellType.STRING.code:
return SMDNumberUtils.parseDouble(cell.getStringCellValue());
case CellType.FORMULA.code:
CellValue cellValue = this.EvaluateCellFormula(cell);
if (!cellValue.getCellTypeEnum().equals(CellType.ERROR))
return cellValue.getNumberValue();
cell.setCellFormula(cell.getCellFormula()
.replaceAll(/[A-Z]+\d+/, { match ->
return "VALUE($match)"
}))
return this.EvaluateCellFormula(cell)
.getNumberValue();
default:
throw new IllegalStateException("Cell Type ${cell.getCellTypeEnum().name} not yet supported!")
}
}
public static CellValue EvaluateCellFormula(Cell cell) {
return cell.getSheet().getWorkbook()
.getCreationHelper()
.createFormulaEvaluator()
.evaluate(cell)
It looks like we need new FormulaEvaluator
every time we evaluate()
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论