poi只对excle中部分函数支持:
支持的函数:
[ABS, ACOS, ACOSH, ADDRESS, AND, ASIN, ASINH, ATAN, ATAN2, ATANH, AVEDEV, AVERAGE, CEILING, CHAR, CHOOSE, CLEAN, CODE, COLUMN, COLUMNS, COMBIN, CONCATENATE, COS, COSH, COUNT, COUNTA, COUNTBLANK, COUNTIF, DATE, DAY, DAYS360, DEGREES, DEVSQ, DOLLAR, ERROR.TYPE, EVEN, EXACT, EXP, FACT, FALSE, FIND, FIXED, FLOOR, FV, HLOOKUP, HOUR, HYPERLINK, IF, INDEX, INDIRECT, INT, INTERCEPT, IPMT, IRR, ISBLANK, ISERROR, ISLOGICAL, ISNA, ISNONTEXT, ISNUMBER, ISREF, ISTEXT, LARGE, LEFT, LEN, LN, LOG, LOG10, LOOKUP, LOWER, MATCH, MAX, MAXA, MEDIAN, MID, MIN, MINA, MINUTE, MIRR, MOD, MODE, MONTH, NA, NOT, NOW, NPER, NPV, ODD, OFFSET, OR, PERCENTILE, PI, PMT, POISSON, POWER, PPMT, PRODUCT, PROPER, PV, RADIANS, RAND, RANK, RATE, REPLACE, REPT, RIGHT, ROMAN, ROUND, ROUNDDOWN, ROUNDUP, ROW, ROWS, SEARCH, SECOND, SIGN, SIN, SINH, SLOPE, SMALL, SQRT, STDEV, SUBSTITUTE, SUBTOTAL, SUM, SUMIF, SUMPRODUCT, SUMSQ, SUMX2MY2, SUMX2PY2, SUMXMY2, T, TAN, TANH, TEXT, TIME, TODAY, TRIM, TRUE, TRUNC, UPPER, VALUE, VAR, VARP, VLOOKUP, WEEKDAY, YEAR]
不支持的函数:
[AREAS, ASC, AVERAGEA, BETADIST, BETAINV, BINOMDIST, CELL, CHIDIST, CHIINV, CHITEST, CONFIDENCE, CORREL, COVAR, CRITBINOM, DATEDIF, DATESTRING, DATEVALUE, DAVERAGE, DB, DBCS, DCOUNT, DCOUNTA, DDB, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, EXPONDIST, FDIST, FINDB, FINV, FISHER, FISHERINV, FORECAST, FREQUENCY, FTEST, GAMMADIST, GAMMAINV, GAMMALN, GEOMEAN, GETPIVOTDATA, GROWTH, HARMEAN, HYPGEOMDIST, INFO, ISERR, ISPMT, KURT, LEFTB, LENB, LINEST, LOGEST, LOGINV, LOGNORMDIST, MDETERM, MIDB, MINVERSE, MMULT, N, NEGBINOMDIST, NORMDIST, NORMINV, NORMSDIST, NORMSINV, NUMBERSTRING, PEARSON, PERCENTRANK, PERMUT, PHONETIC, PROB, QUARTILE, REPLACEB, RIGHTB, RSQ, SEARCHB, SKEW, SLN, STANDARDIZE, STDEVA, STDEVP, STDEVPA, STEYX, SYD, TDIST, TIMEVALUE, TINV, TRANSPOSE, TREND, TRIMMEAN, TTEST, TYPE, USDOLLAR, VARA, VARPA, VDB, WEIBULL, ZTEST]
当我们用到不支持的函数时需要手动注册下面说下怎么手动注册函数。
最近在解析excle中遇到了NORMINV(正态分布)这个函数:
首先注册时我们只需要注册一遍(注册重复则会报错)所以我写了个监听在bean加载完后注册函数
package com.tsingyun.iec104.listener;
import org.apache.poi.ss.formula.eval.FunctionEval;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import com.tsingyun.iec104.poi.registerFunction;
/**
* @author gyx
* @date 2018年7月20日 下午2:55:05
*
*/
@Component
public class Listener implements ApplicationListener{
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//注册公式
FunctionEval.registerFunction("NORMINV", new registerFunction());
}
}
其次我们创建公式类(需要导入commons-math3包 gradle中则是 compile('org.apache.commons:commons-math3:3.6.1'))
package com.tsingyun.iec104.poi;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author gyx
* @date 2018年8月9日 下午5:17:37
*
*/
public class registerFunction implements Function{
@Override
public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
String argss = args[0].toString()+args[1].toString()+args[2].toString();
List list = extractMessageByRegular(argss);
//new NormalDistribution(mean,standard_dev)
NormalDistribution normalDistributioin = new NormalDistribution(Double.valueOf(list.get(1)), Double.valueOf(list.get(2)));
//double S1 = normalDistributioin.cumulativeProbability(Double.valueOf(list.get(0)));
//normalDistributioin.inverseCumulativeProbability(probability)
double S2 = normalDistributioin.inverseCumulativeProbability(Double.valueOf(list.get(0)));
return new NumberEval(S2);
}
/**
* 使用正则表达式提取中括号中的内容
* @param msg
* @return
*/
public static List extractMessageByRegular(String msg){
List list=new ArrayList();
Pattern p = Pattern.compile("(\\[[^\\]]*\\])");
Matcher m = p.matcher(msg);
while(m.find()){
list.add(m.group().substring(1, m.group().length()-1));
}
return list;
}
}
这时我们的NORMINV公式则注册好了。
当遇到NORMINV公式时 则可更新公式
/**
* 传入cell的值,进行cell值类型的判断,并返回String类型
*
* @param cell
* @return
*/
private String getCellValue(XSSFCell cell) {
String value = null;
if(cell==null){
return "";
}
// 简单的查检列类型
switch (cell.getCellType()) {
case XSSFCell.CELL_TYPE_STRING:// 字符串
value = cell.getRichStringCellValue().toString();
break;
case XSSFCell.CELL_TYPE_NUMERIC:// 数字
long dd = (long) cell.getNumericCellValue();
value = dd + "";
break;
case XSSFCell.CELL_TYPE_BLANK:
value = "";
break;
case XSSFCell.CELL_TYPE_FORMULA:
eval.evaluateFormulaCell(cell); // 更新公式
try {
value = String.valueOf(cell.getNumericCellValue());
} catch (IllegalStateException e) {
value = String.valueOf(cell.getRichStringCellValue());
}
break;
case XSSFCell.CELL_TYPE_BOOLEAN:// boolean型值
value = String.valueOf(cell.getBooleanCellValue());
break;
case XSSFCell.CELL_TYPE_ERROR:
value = String.valueOf(cell.getErrorCellValue());
break;
default:
System.out.println("default");
break;
}
return value;
}