完整代码地址:https://github.com/kwang2003/formular
基于antlr4实现Excel公式计算功能,目前已经实现的函数操作:
-
负数(-)
-
说明
负数要带括号因为负号可能被解析成操作符减号
-
示例
private static void testNegativeNumber() { assertEquals("(-1)", -1D); assertEquals("(-1.2)", -1.2D); assertEquals("(-3456)", -3456D); assertEquals("(-343)", -343D); assertEquals("(-3.43)", -3.43D); }
-
-
加法运算+
-
说明
数据之间做加法运算
-
示例
private static void testAdd() { assertEquals("(1+1)", 2D); assertEquals("1+2", 3D); assertEquals("1+ABS(2)", 3D); assertEquals("(1)+(2)", 3D); assertEquals("(1+4.2)", 5.2D); assertEquals("1+max(1,2,3)", 4D); assertEquals("1+max(1,2,ABS(3))", 4D); }
-
-
减法运算-
-
说明
数字之间进行减法运算
-
示例
public static void testAddSubstract() { assertEquals("(-1)+3", 2D); assertEquals("(-1)-(-2)", 1D); assertEquals("3+2+1", 6D); assertEquals("3+(-8)+2+1", -2D); assertEquals("3-2+1", 2D); assertEquals("3.5-2.2+1", 2.3D); assertEquals("1-6+abs(3)+max(3,abs((-4)),abs(6))", 4D); assertEquals("3-2+10", 11D); } private static void testAdd() { assertEquals("(1+1)", 2D); assertEquals("1+2", 3D); assertEquals("1+ABS(2)", 3D); assertEquals("(1)+(2)", 3D); assertEquals("(1+4.2)", 5.2D); assertEquals("1+max(1,2,3)", 4D); assertEquals("1+max(1,2,ABS(3))", 4D); }
-
-
括弧运算符()
-
说明
括弧运算符包含的表达式,其结果还是表达式本身的值
-
示例
private static void testParens() { assertEquals("(1)", 1D); assertEquals("((1))", 1D); }
-
-
乘法运算*
-
说明
数值之间相乘
-
示例
private static void testMultiply() { assertEquals("3*2", 6D); assertEquals("3.2*2", 6.4D); assertEquals("3.2*0", 0D); assertEquals("3*2*5", 30D); assertEquals("3*abs(2)*5", 30D); assertEquals("3*2*max(5,3,2)", 30D); assertEquals("1+2*3", 7D); assertEquals("1+(2*3)", 7D); assertEquals("(1+2)*3", 9D); assertEquals("1+2*(4+6)", 21D); assertEquals("1+2*(4+6)-1+10", 30D); assertEquals("1+2*(4-6)-1+10", 6D); }
-
-
除法运算
-
说明
数值之间除法运算
-
示例
private static void testDivide() { assertEquals("3/2", 1.5D); assertEquals("(-3)/(-2)", 1.5D); assertEquals("3/1.5", 2D); assertEquals("(-3)/1.5", -2D); assertEquals("3/(-1.5)", -2D); assertEquals("3/2+3", 4.5D); assertEquals("3/2/1.5", 1D); assertEquals("abs(3/2)", 1.5D); assertEquals("1-3/2+2", 1.5D); assertEquals("1+8/(2+2)-5", -2D); assertEquals("18/3*4", 24D); assertEquals("5*8/2", 20D); assertEquals("5*8/2-18", 2D); assertEquals("1+3*8/(2+2)-18/3*4", -17D); }
-
-
-
说明
取绝对值
-
语法
ABS(number)
ABS 函数语法具有下列参数
- number 必需。 需要计算其绝对值的实数。
-
示例
private static void testAbs() { assertEquals("abs(1)", 1D); assertEquals("abs((-1))", 1D); assertEquals("abs(10)", 10D); assertEquals("abs(10.1)", 10.1D); assertEquals("ABS((-11.0))", 11D); }
-
-
-
说明
返回一组值中的最大值。
-
语法
MAX(number1, [number2], ...)
MAX 函数语法具有下列参数
- number1, number2, ... Number1 是必需的,后续数字是可选的。 要从中查找最大值的 1 到 255 个数字。
-
示例
/** * max函数测试 */ private static void testMax() { assertEquals("max(1)", 1D); assertEquals("MAX(1)", 1D); assertEquals("max(1,2)", 2D); assertEquals("max(1,2,3)", 3D); assertEquals("max(1,1.1,3)", 3D); assertEquals("max(1,(-1.1),3)", 3D); assertEquals("max(abs((-1)),1.1,3)", 3D); assertEquals("max(abs((-1)),aBs(1.1),max(3,4,6))", 6D); }
-
-
-
说明
返回一组值中的最小值。
-
语法
MIN(number1, [number2], ...)
MIN 函数语法具有下列参数
- number1, number2, ... Number1 是必需的,后续数字是可选的。 要从中查找最小值的 1 到 255 个数字。
-
示例
/** * min函数测试 */ private static void testMin() { assertEquals("min(1)", 1D); assertEquals("MIN(1)", 1D); assertEquals("min(1,2)", 1D); assertEquals("min(1,2,3)", 1D); assertEquals("min(1,1.1,3)", 1D); assertEquals("min(1,(-1.1),3)", -1.1D); assertEquals("min(abs((-1)),1.1,3)", 1D); assertEquals("min(abs((-1)),aBs(1.1),min(3,4,6))", 1D); }
-
-
-
说明
ROUND 函数将数字四舍五入到指定的位数。 例如,如果单元格 A1 包含 23.7825,而且您想要将此数值舍入到两个小数位数,可以使用以下公式:
=ROUND(A1, 2)
此函数的结果为 23.78。
-
语法
ROUND(number, num_digits)
ROUND 函数语法具有下列参数:
- number 必需。 要四舍五入的数字。
- num_digits 必需。 要进行四舍五入运算的位数。
-
备注
- 如果 num_digits 大于 0(零),则将数字四舍五入到指定的小数位数。
- 如果 num_digits 等于 0,则将数字四舍五入到最接近的整数。
如果 num_digits 小于 0,则将数字四舍五入到小数点左边的相应位数。(暂不支持)- 若要始终进行向上舍入(远离 0),请使用 ROUNDUP 函数。
- 若要始终进行向下舍入(朝向 0),请使用 ROUNDDOWN 函数。
- 若要将某个数字四舍五入为指定的倍数(例如,四舍五入为最接近的 0.5 倍),请使用 MROUND 函数。
-
示例
private static void testRound() { assertEquals("round(23.7825)", 23.78D); assertEquals("round(2,2)", 2.00D); assertEquals("round(2.123,2)", 2.12D); assertEquals("round(2.126,2)", 2.13D); assertEquals("round((-2.126),2)", -2.13D); assertEquals("round(abs(2.126),2)", 2.13D); }
-
-
-
说明
将数字向下舍入到最接近的整数
-
语法
Int( number )
INT 函数语法具有下列参数:
- Number 必需。 需要进行向下舍入取整的实数
-
示例
private static void testInt() { assertEquals("int(1.12)", 1D); assertEquals("INT((-8.9))", -9D); assertEquals("int(1.12+2)", 3D); assertEquals("int(cos(min(3,0,5)))", 1D); }
-
-
-
说明 对值和期待值进行逻辑比较。IF 函数最简单的形式表示:
- 如果(内容为 True,则执行某些操作,否则就执行其他操作)
-
语法
IF(logical_test, value_if_true, value_if_false)
-
示例
private static void testIf() { assertEquals("IF(1>2,3,4)", 4D); assertEquals("IF(1<2,3,4)", 3D); assertEquals("IF(1=1,1,4)", 1D); assertEquals("IF(1>=1,1,4)", 1D); assertEquals("IF(1>=1.1,1,8)", 8D); assertEquals("IF(1+2>=1,1,4)", 1D); assertEquals("IF(1-2>=1,1,4)", 4D); assertEquals("IF(3/(-1.5)>0,abs(1.5),min(5,6))", 5D); assertEquals("IF(1+3*8/(2+2)-18/3*4>2,3,4)", 4D); assertEquals("IF(1<>2,3,4)", 3D); assertEquals("IF(1<>1,3,4)", 4D); assertEquals("IF(1>2,3,IF(2>4,6,7))", 7D); }
-
-
-
说明
使用 OR 函数,它是一个逻辑函数,用于确定测试中的所有条件是否均为 TRUE。
-
语法 OR(logical_test1,[logical_test2],...)
-
示例
private static void testOr() { assertEquals("if(OR(3>4,1>2),1,2)", 2D); assertEquals("if(OR(FALSE,TRUE),10,2)", 10D); assertEquals("if(OR(1>2,TRue),1,2)", 1D); assertEquals("IF(OR(FALSE,OR(3>2)),3,2)", 3D); }
-
-
-
说明
使用 AND 函数,它是一个逻辑函数,用于确定测试中的所有条件是否均为 TRUE。
-
语法 AND(logical_test1,[logical_test2],...)
-
示例
private static void testAnd() { assertEquals("if(And(3>4,1>2),1,2)", 2D); assertEquals("if(And(FALSE,TRUE),10,2)", 2D); assertEquals("if(And(1>2,TRue),1,2)", 2D); assertEquals("IF(And(FALSE,OR(3>2)),3,2)", 2D); }
-
-
-
说明
NOT 函数会对其参数的值进行求反。
NOT 函数的一个常见用途是扩展执行逻辑测试的其它函数的有效性。例如,IF 函数将执行逻辑测试,并在计算结果为 TRUE 时返回一个值,在计算结果为 FALSE 时返回另一个值。通过将 NOT 函数作为 IF 函数的 logical_test 参数,你可以测试众多而不仅是单个条件。
-
语法
NOT(逻辑函数)
-
示例
private static void testNot() { assertEquals("if(not(true),3,1)", 1D); assertEquals("if(not(and(3>1,4>2)),3,1)", 1D); assertEquals("if(not(1>2),1,2)", 1D); }
-
-
-
说明
返回参数的平均值(算术平均值)。 例如,如果范围A1,A20 包含数字,则公式 =AVERAGE(A1,A20) 将返回这些数字的平均值。
-
语法
AVERAGE(number1, [number2], ...)
AVERAGE 函数语法具有下列参数:
- Number1 必需。 要计算平均值的第一个数字、单元格引用或单元格区域
- Number2, ... 可选。 要计算平均值的其他数字、单元格引用或单元格区域,最多可包含 255 个
-
示例
public static void testAverage() { assertEquals("Average(3)", 3D); assertEquals("Average(3,3)", 3D); assertEquals("Average(2,4)", 3D); assertEquals("Average(3.4,2.6)", 3D); assertEquals("Average(3,average(3))", 3D); assertEquals("Average(3+3,2)", 4D); assertEquals("Average(max(3,4,5),7)", 6D); }
-
-
-
说明
返回数字乘幂的结果。
-
语法
POWER(number, power) POWER 函数语法具有下列参数:
- Number 必需。 基数。 可为任意实数
- power 必需。 基数乘幂运算的指数
-
备注
可以使用“^”代替 POWER,以表示基数乘幂运算的幂,例如 5^2。
-
示例
public static void testPower() { assertEquals("5^2", 25D); assertEquals("2^10", 1024D); assertEquals("6^2/4", 9D); assertEquals("2+5^2", 27D); assertEquals("POWER(5,2)", 25D); assertEquals("POWER(1,2)", 1D); assertEquals("POWER(3,3)", 27D); assertEquals("POWER(max(4,5,3),2)", 25D); assertEquals("POWER(5+2,2)", 49D); assertEquals("POWER(5-2*2+1,2)", 4D); }
-
-
-
说明
返回数字 3.14159265358979(数学常量 pi),精确到 15 个数字。
-
语法
标准偏差
PI 函数语法没有参数
-
示例
private static void testPi() { assertEquals("pi()", Math.PI); assertEquals("PI()*(3^2)", 28.274333882308138);//圆的面积 }
-
-
-
说明
返回已知角度的正弦
-
语法
Sin( number )
SIN 函数语法具有下列参数:
- Number 必需。 需要求正弦的角度,以弧度表示。
-
备注
如果参数是以度数表示的,请将它乘以 PI()/180 或使用 RADIANS 函数将它转换为弧度。
-
示例
private static void testSin() { assertEquals("sin(0)", 0D); assertEquals("sin(min(3,0,5))", 0D); }
-
-
-
说明
返回已知角度的余弦值
-
语法
COS(number)
COS 函数语法具有下列参数:
- “数字” 必需。 想要求余弦的角度,以弧度表示。
-
备注
如果角度是以度表示的,则可将其乘以 PI()/180 或使用 RADIANS 函数将其转换成弧度。
-
示例
private static void testCos() { assertEquals("cos(0)", 1D); assertEquals("cos(min(3,0,5))", 1D); }
-
-
-
说明 返回数字的反余弦值。 反余弦值是指余弦值为 number 的角度。 返回的角度以弧度表示,弧度值在 0(零)到 pi 之间。
-
语法
ACOS(number)
ACOS 函数语法具有以下参数:
- Number 必需。 所求角度的余弦值,必须介于 -1 到 1 之间
-
示例
private static void testAcos() { assertEquals("ACOS((-0.5))*180/PI()", 120.00000000000001D); }
-
-
-
说明
返回数字的反正弦值。 反正弦值是指正弦值为 number 的角度。 返回的角度以弧度表示,弧度值在 -pi/2 到 pi/2 之间。
-
语法
ASIN(number)
ASIN 函数语法具有以下参数:
- Number 必需。 所求角度的正弦值,必须介于 -1 到 1 之间。
-
示例
private static void testAsin() { assertEquals("ASIN((-0.5))*180/PI()", -30.000000000000004D); assertEquals("ASIN((-0.5))", -0.5235987755982989D); }
-
-
-
说明
返回已知角度的正切
-
语法
TAN(number)
TAN 函数语法具有下列参数:
- Number 必需。 要求正切的角度,以弧度表示。
-
示例
private static void testTan() { assertEquals("TAN(0.785)", 0.9992039901050427); assertEquals("TAN(45*PI()/180)", 0.9999999999999999D); }
-
-
-
说明
返回数字的反正切值。 反正切值是指正切值为 number 的角度。 返回的角度以弧度表示,弧度值在 -pi/2 到 pi/2 之间。
-
语法
ATAN(number)
ATAN 函数语法具有以下参数:
- Number 必需。 所求角度的正切值
-
示例
private static void testAtan() { assertEquals("ATAN(1)", 0.7853981633974483); assertEquals("ATAN(1)*180/PI()", 45D); }
-
-
-
说明
将度数转换为弧度
-
语法
RADIANS(angle)
RADIANS 函数语法具有下列参数:
- Angle 必需。 要转换的以度数表示的角度
-
示例
private static void testRadians() { assertEquals("radians(270)", 4.71238898038469); }
-
-
-
说明
RAND 返回了一个大于等于 0 且小于 1 的平均分布的随机实数。每次计算工作表时都会返回一个新的随机实数。
-
语法
RAND
RAND 函数语法没有参数。
-
示例
private static void testRand() throws Exception{ System.out.println(FormularCompiler.compile("rand()").doubleValue()); System.out.println(FormularCompiler.compile("rand()*(100+10)").doubleValue()); }
-
-
-
说明
返回正的平方根
-
语法
SQRT(number)
SQRT 函数语法具有下列参数:
- Number 必需。 要计算其平方根的数字。
-
示例
private static void testSqrt() { assertEquals("sqrt(9)", 3d); assertEquals("sqrt(2*5-6)", 2D); assertEquals("1*sqrt(9)+5*2", 13d); assertEquals("sqrt(max(9,5,min(1,2,7)))", 3d); }
-
-
-
说明
SUM 函数是一个数学和三角函数,可将值相加。你可以将单个值、单元格引用或是区域相加,或者将三者的组合相加。
-
语法
SUM(number1, [number2], ...)
-
示例
private static void testSum() { assertEquals("sum(1)", 1D); assertEquals("sum(1,2)", 3D); assertEquals("2+sum(1,2)", 5D); assertEquals("2*3+sum(1,2)*5", 21D); assertEquals("2*3+sum(1,min(2,3,4))*5", 21D); }
-
-
-
说明
返回参数的平方和
-
语法
SUMSQ(number1, [number2], ...)
SUMSQ 函数语法具有下列参数:
- number1, number2, ... Number1 是必需的,后续数字是可选的。 要对其求平方和的 1 到 255 个参数。 也可以用单一数组或对某个数组的引用来代替用逗号分隔的参数
-
示例
private static void testSumSq() { assertEquals("sumsq(1)", 1D); assertEquals("sumsq(1,2)", 5D); assertEquals("sumsq(3,4)", 25D); assertEquals("1+sumsq(1,2)*2", 11D); }
-
-
-
说明
返回 e 的 n 次幂。 常数 e 等于 2.71828182845904,是自然对数的底数
-
语法
Exp( number )
EXP 函数语法具有下列参数:
- Number 必需。 底数 e 的指数
-
示例
private static void testExp() { assertEquals("exp(1)", 2.718281828459045); assertEquals("exp(2)", 7.38905609893065); }
-
-
-
说明
将弧度转换为度
-
语法
DEGREES(angle)
DEGREES 函数语法具有下列参数:
- 角度 必需。 要转换的角度,以弧度表示。
-
示例
private static void testDegrees() { assertEquals("DEGREES(PI())", 180D); }
-
-
-
说明
返回两数相除的余数。 结果的符号与除数相同。
-
语法
MOD(number, divisor)
MOD 函数语法具有下列参数:
- Number 必需。 要计算余数的被除数。
- Divisor 必需。 除数。
-
示例
private static void testMod() { assertEquals("MOD(3, 2)", 1D); assertEquals("MOD((-3), 2)", 1D); }
-
- jdk1.8
- antlr4 4.5,antlr4-maven-plugin 4.5
注意:把项目依赖升级到最新版本的antlr 4.7和antlr4-maven-plugin 4.7后不能正常运行,原因暂未定位
antlr4
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
<version>4.5</version>
</dependency>
添加maven插件antlr4-maven-plugin
<build>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.5</version>
<executions>
<execution>
<id>antlr</id>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
<configuration>
<arguments>
<argument>-no-listener</argument>
<argument>-visitor</argument>
</arguments>
<treatWarningsAsErrors>true</treatWarningsAsErrors>
</configuration>
</plugin>
</plugins>
</build>
测试用例位于 com.pachiraframework.formular.App.main() 方法中
参考资料