【问题标题】:Library to evaluate excel/other language expression evaluation in java without using excel在不使用 excel 的情况下在 java 中评估 excel/其他语言表达式评估的库
【发布时间】:2019-08-02 10:20:00
【问题描述】:

我一直在互联网上搜索一个可以在java中评估类似excel公式的表达式的库。公式没有嵌入到excel中。

假设值不在 excel 中假设 3 个变量 abc 我想要一个 java 中的评估器,它给出一个字符串,如CONCAT(a,b,c),用 excel 表达式或其他一些表达式语言,可以给我输出。

我在网上找到了一些java的表达式评估器库,但是我需要定义自己的表达式语言,有没有直接使用excel语言或其他语言的东西?

我已经查看了 apache POIjxls 还查看了 jsp.el,据我所知 poijxls 对已经嵌入在 excel 文件中的公式进行评估,或者我们需要创建一个实际运行公式的电子表格,imo 将比在 java 中运行公式更重。对于jsp.el,我必须定义自己的表达语言,这还不够健壮。

【问题讨论】:

  • 您是否尝试过对其进行基准测试?使用 Apache POI 在内存中创建单个工作表,其中包含一些公式,并且评估应该非常快
  • 正如 Axel 已经回答的那样,但此工作簿不一定要存储在某个地方。它也只能在随机存取存储器中是我想知道的。我认为这是在计算机中创建一个 excel。现在,我将进行基准测试并检查我是否处于时间紧缩状态。

标签: java excel excel-formula apache-poi expression-evaluation


【解决方案1】:

apache poiWorkbookEvaluator 需要一个工作簿是正确的。并且由于您正在谈论评估“类似 Excel 公式的表达式”,因此这是必要的,因为此类公式中的所有变量都必须是该工作簿中的单元格引用或名称。当abcExcel 名称时,您给定的示例CONCATENATE(a,b,c) 只能用作Excel 公式。否则会导致Excel 中的#Name? 错误。顺便说一句:Excel 函数是 CONCATENATE 而不是 CONCAT

但是这个工作簿不一定要存储在某个地方。它也只能在随机存取存储器中。

并且公式本身不需要在表格中的某个地方。由于存在WorkbookEvaluator.evaluate(java.lang.String formula, CellReference ref),因此公式也可以作为字符串给出。

例子:

import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Name;

import org.apache.poi.ss.formula.BaseFormulaEvaluator;
import org.apache.poi.ss.formula.WorkbookEvaluator;

import org.apache.poi.ss.formula.eval.*;

import org.apache.poi.ss.util.CellReference;

public class EvaluateExcelFunctions {

 static Object evaluateExcelFormula(String formula, Workbook workbookWithVariables) {
  if (workbookWithVariables.getNumberOfSheets() < 1) workbookWithVariables.createSheet();
  CellReference reference = new CellReference(workbookWithVariables.getSheetName(0), 0 , 0, false, false);
  CreationHelper helper = workbookWithVariables.getCreationHelper();
  FormulaEvaluator formulaevaluator = helper.createFormulaEvaluator();
  WorkbookEvaluator workbookevaluator = ((BaseFormulaEvaluator)formulaevaluator)._getWorkbookEvaluator();
  ValueEval valueeval = null;
  try {
   valueeval = workbookevaluator.evaluate(formula, reference);
  } catch (Exception ex) {
   return ex.toString();
  }
  if (valueeval instanceof StringValueEval) {
   String result = ((StringValueEval)valueeval).getStringValue();
   return result;
  } else if (valueeval instanceof NumericValueEval) {
   double result = ((NumericValueEval)valueeval).getNumberValue();
   return result;
  } else if (valueeval instanceof ErrorEval) {
   String result = ((ErrorEval)valueeval).getErrorString();
   return result;
  }
  return null;  
 }

 public static void main(String[] args) throws Exception {

  Workbook workbook = 
   //new XSSFWorkbook();
   new HSSFWorkbook();

  Name name;
  String formula;
  Object result;

  // example 1 concatenating strings - your example
  name = workbook.createName();
  name.setNameName("_a");
  name.setRefersToFormula("\"Text A \"");
  name = workbook.createName();
  name.setNameName("_b");
  name.setRefersToFormula("\"Text B \"");
  name = workbook.createName();
  name.setNameName("_c");
  name.setRefersToFormula("\"Text C \"");

  formula = "CONCATENATE(_a, _b, _c)";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  // example 2 Pythagorean theorem
  name = workbook.getName("_a"); 
  name.setRefersToFormula("12.34");
  name = workbook.getName("_b");
  name.setRefersToFormula("56.78");

  formula = "SQRT(_a^2 + _b^2)";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  // example 3 complex math formula
  name = workbook.getName("_a"); 
  name.setRefersToFormula("12.34");
  name = workbook.getName("_b");
  name.setRefersToFormula("56.78");
  name = workbook.getName("_c");
  name.setRefersToFormula("90.12");

  formula = "((_a+_b+_c)*_c/_b-_a)/2";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  // example 4 faulty formulas
  name = workbook.getName("_a"); 
  name.setRefersToFormula("56.78");
  name = workbook.getName("_b");
  name.setRefersToFormula("190.12");
  name = workbook.getName("_c");
  name.setRefersToFormula("\"text\"");

  formula = "_a + _c";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  formula = "((_a + _b";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  formula = "_a \\ 2";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  formula = "_a^_b";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  formula = "_a/(_b-_b)";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  formula = "CONCAT(_a, _b)";
  result = evaluateExcelFormula(formula, workbook);
  System.out.println(result);

  workbook.close();
 }  
}

此代码使用apache poi 4.1.0 进行测试。

注意,Excel 名称不能是所有可能的变量名称。例如,Excel 名称不能是 cC,因为这会与可能的 R1C1 单元格引用相冲突。这就是为什么我将我的名字命名为 _a_b_c

【讨论】:

  • 非常感谢。对不起,如果问题有点不清楚。我不确定如何正确地构图。但这是我一直在寻找的。我现在将与自制的公式评估器进行基准测试,看看性能差异是否很大。 但此工作簿不一定要存储在某处。它也只能在随机存取存储器中。是我想知道的。
【解决方案2】:

要使用 IF 函数,我必须创建一个 Cell 实例来防止 NullPointerException:

Cell cell = workbookWithVariables.getSheet(workbookWithVariables.getSheetName(0)).createRow(0).createCell(0);
CellReference reference = new CellReference(cell);

【讨论】:

    猜你喜欢
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-07
    相关资源
    最近更新 更多