Oracle 函数实现动态解析公式字符串

本文介绍了如何在Oracle中利用函数动态解析不包含嵌套括号的计算公式,例如a+b*(c+d)/e-f*(g-h)。讨论了正则表达式的使用,以及在匹配符号时的转义规则。
摘要由CSDN通过智能技术生成

在工作当中,需要利用函数实现动态解析公式字符串的功能。由于时间有限,以及业务需求,目前不支持一个计算公式中同时出现两个小括号叠加出现的情况。如a+(b+(c-d))这种情况,但对于类似a+b*(c+d)/e-f*(g-h) 的情况是可以处理的。代码如下:

 需要注意的是,对于正则匹配,如果写成 REGEX_SUBSTR(str, '[+]') 的形式,不需要进行转义,如果写成 REGEX_SUBSTR(str, '\+') 的形式,则需要转义。

CREATE OR REPLACE 
FUNCTION FUNC_GET_CALC(in_calc NVARCHAR2) RETURN  NUMBER IS 
 RESULT NUMBER;
BEGIN
       CASE
 --括号出现在字符串开头
          WHEN INSTR(in_calc, '(') =  1 THEN  --括号有可能出现在字符串开始、中间、末尾三个地方
           CASE 
							WHEN REGEXP_SUBSTR(in_calc, '[0-9|#]', INSTR(in_calc, '(') + 1)  IS NOT NULL THEN --括号后是指标,暂时不考虑括号后还有括号的情况
								 CASE 
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, ')') + 1, 1) = '+' THEN RETURN ((FUNC_GET_CALC(SUBSTR(in_calc,2,INSTR(in_calc, ')')-2))) + FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2) )) ; --')'后是'+'
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, ')') + 1, 1) = '-' THEN RETURN ((FUNC_GET_CALC(SUBSTR(in_calc,2,INSTR(in_calc, ')')-2))) - FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2) )) ;  --')'后是'+'
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, ')') + 1, 1) = '*' THEN RETURN ((FUNC_GET_CALC(SUBSTR(in_calc,2,INSTR(in_calc, ')')-2))) * FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2) )) ; --')'后是'+'
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, ')') + 1, 1) = '/' THEN RETURN ((FUNC_GET_CALC(SUBSTR(in_calc,2,INSTR(in_calc, ')')-2))) / FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2) )) ; --')'后是'+' 
								 END CASE;
           END CASE;
           --括号出现在字符串末尾 
					 WHEN INSTR(in_calc, '(') >  1 AND  INSTR(in_calc, ')') = LENGTH(in_calc)  THEN  --括号出现在字符串末尾
           CASE 
							WHEN REGEXP_SUBSTR(in_calc, '[0-9|#]', INSTR(in_calc, '(') + 1)  IS NOT NULL  THEN --括号后是指标,暂时不考虑括号后还有括号的情况
								 CASE 
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, '(') - 1, 1) = '+' THEN RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) + (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 , LENGTH(in_calc)-INSTR(in_calc, '(') - 1 )))) ; --'('前是'+'
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, '(') - 1, 1) = '-' THEN RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) - (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,LENGTH(in_calc)-INSTR(in_calc, '(')  - 1 )))) ;  --'('前是'+'
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, '(') - 1, 1) = '*' THEN RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) * (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,LENGTH(in_calc)-INSTR(in_calc, '(')  - 1 )))) ; --'('前是'+'
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, '(') - 1, 1) = '/' THEN RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) / (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,LENGTH(in_calc)-INSTR(in_calc, '(')  - 1 )))) ; --'('前是'+' 
								 END CASE;
           END CASE;

--括号出现在字符串中间
          WHEN INSTR(in_calc, '(') >  1 AND  INSTR(in_calc, ')') < LENGTH(in_calc)  THEN  --括号出现在字符串中间
           CASE 
							WHEN REGEXP_SUBSTR(in_calc, '[0-9|#]', INSTR(in_calc, '(') + 1)  IS NOT NULL  THEN --括号后是指标,暂时不考虑括号后还有括号的情况
								 CASE 
											WHEN 	SUBSTR(in_calc, INSTR(in_calc, '(') - 1, 1) = '+' THEN 
                         CASE
													  	WHEN 	SUBSTR(in_calc, INSTR(in_calc, ')') + 1, 1) = '+' THEN RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) + (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,(INSTR(in_calc, ')')-INSTR(in_calc, '(')-1)))) + FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2) )) ; --')'后是'+'
															WHEN 	SUBSTR(in_calc, INSTR(in_calc, ')') + 1, 1) = '-' THEN RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) + (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,(INSTR(in_calc, ')')-INSTR(in_calc, '(')-1)))) - FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2) )) ; --')'后是'+'
															WHEN 	SUBSTR(in_calc, INSTR(in_calc, ')') + 1, 1) = '*' THEN   --存在运算符优先级的问题,因此需要特殊处理 如2*(2+3)/2+1 , 如果拆分成2 、*、(2+3)、/、2+1 ,五个部分,则结果出错
																		IF   REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[+|-|*|/|(]') > 0 THEN
																						CASE 
																						WHEN   REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[+]') > 0  THEN 
																								RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) + (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,(INSTR(in_calc, ')')-INSTR(in_calc, '(')-1)))) * FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2,  REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[+]') -1 )) + FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2 + REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[+]')  ) ) ) ; --')'后是'+'
																										
																						WHEN   REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[\-]') > 0  THEN 
																								RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) + (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,(INSTR(in_calc, ')')-INSTR(in_calc, '(')-1)))) * FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2,  REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[\-]') -1 )) - FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2 + REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[\-]') ) ) ) ; --')'后是'+'
																						
																						WHEN   REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[\*]') > 0  THEN 
																								RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) + (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,(INSTR(in_calc, ')')-INSTR(in_calc, '(')-1)))) * FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2,  REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[\*]') -1 )) * FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2 + REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[\*]') ) ) ) ; --')'后是'+'
																						
																						WHEN   REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc, ')')+2), '[/]') > 0  THEN 
																								RETURN (FUNC_GET_CALC(SUBSTR(in_calc,1,INSTR(in_calc, '(')-2)) + (FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, '(') + 1 ,(INSTR(in_calc, ')')-INSTR(in_calc, '(')-1)))) * FUNC_GET_CALC(SUBSTR(in_calc,INSTR(in_calc, ')') + 2,  REGEXP_INSTR(SUBSTR(in_calc, INSTR(in_calc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值