一 三目运算
java和其他主流语言一样,使用 “条件?True结果:False结果” 的格式;python搞特殊,最开始没有三目运算,只能用 and or来模拟,还会有短路的问题。py2.5之后才加了三目运算 “True结果 if 条件 else False结果”。还可以用np.where,但需要额外导numpy库。
某些场景,为了所谓的动态,会将参数因子存在数据库中,后台计算时去数据库取因子。有时甚至直接把java写好的公式放在数据库中,取出来eval一下就得到结果。这时用py做同一件事(不论是py重构项目还是写测试脚本)就难受了。
二 解决方案 (推荐第四种
1 jpype运行java代码片段(视情况
就如java可以用runtime之类的东西运行其他代码、脚本一样,python有jpype用来运行java代码片段。但需要安装jpype库和jre环境,原理就是由这个库创建一个jvm运行java代码。
2 python调用jar包(不推荐
其实就是操作外部文件,而且好像不能得到返回值。
以上很暴力,下面专说三目运算
3 if-else强行解析(不推荐
也很暴力,不可取。三木运算式本身就可以置入公式中成为一部分,强行拆成三块再解析出条件部分费力不讨好。
4 转换为python的三目运算式(推荐
最终我使用的是这种方式。对于python和其他语言中条件和True结果的位置不同我是很不满的,搞什么特殊?
首先说明几个重点:
a 还是要将条件、True、False三部分精确拆分重组,注意嵌套三目的场景;
就比如上图中的嵌套,能找到规律嘛?
结论我就说了:尾部两个符号为?:,那么尾部就是个可以转换的三目式;其余部分找到“? :”后还要判断后面一个符号,若为“? : :”则“? :”部分是可以转换的底层三目式;若为“? : ?”则“? :”部分还嵌套包含着三目,不可转换。
我的设计就是一轮一轮来,每次找出底层可以转换的三目进行转换,转换完成后由于没有了?:,下轮就不会再视此为三目式,类似递归。
这当然还是有问题的,见b
b 注意优先级,例如括号。
例如:
2>1 ? 1 : new BigDecimal(1).multiply(5>2 ? new BigDecimal(2) : new BigDecimal(3))
//bigdecimal为java的一种数据类型,可进行任意数量级的计算,multiply为其乘法
不注意括号造成的分割的话,就会把“new BigDecimal(1).multiply(5>2”这一大块都当成嵌套三目的条件,这当然是错的,这里是1乘以嵌套三目式的结果才对。
因此在开始寻找底层三目进行转换之前,要先对括号分组,各个括号内进行转换,最终消除括号。
那么括号最终可以消除吗?
c
答案是括号不能乱删。在所有步骤开始之前,最好把java的一些方法replace掉,例如Integer.parse,例如new BigDecimal,例如Xxx.getXxx()等等,换成python的int,Decimal,Xxx['Xxx'],(java的实体类入参在py中处理成字典)可以少些括号,减少步骤b的压力。
emmm早上遇到过这个问题现在还原不出来,总之每处理完一轮,给每个三目加个括号总没错
三 代码实现
from decimal import *
class 类():
#根据java代码、参数字典转换并计算
@staticmethod
def 计算(expression, 转换成字典的实体类):
#替换java转型、数据类型代码为python代码
expression = 类.replaceParam(expression)
#括号分组,检查是否有括号包裹的高优先级三目运算
lc = []
rc = []
for charIndex in range(len(expression)):
if expression[charIndex] == '(':
lc.append(charIndex)
elif expression[charIndex] == ')':
rc.append(charIndex)
coupleDict = dict.fromkeys(lc, None)
for li in sorted(coupleDict.keys(), reverse = True):
for ri in sorted(rc):
if ri > li:
coupleDict[li] = ri
rc.remove(ri)
break
for keyName in sorted(coupleDict.keys(), reverse = True):
if expression[int(keyName): coupleDict[keyName]].find('?') != -1:
expression = expression[0: int(keyName)] + CaculateOperator.analyzeOperator(expression[int(keyName) + 1: coupleDict[keyName] - 1]) + expression[coupleDict[keyName]: len(expression)]
expression = CaculateOperator.analyzeOperator(expression)
return round(eval(expression), 0)
#解析当前最底层的三目运算式
@staticmethod
def analyzeOperator(expressionStr):
#循环转换最底层的三目运算式,直到完成
while expressionStr.find('?') != -1:
#获得?、:索引列表,列表项为包含索引、符号的字典
symbolList = []
index = 0
for charStr in expressionStr:
if charStr == '?':
symbolList.append({'index': index, 'symbol': '?'})
elif charStr == ':':
symbolList.append({'index': index, 'symbol': ':'})
index += 1
#寻找下一项和下下项都为冒号的问号,将此组三目运算转换
index = len(symbolList) - 2
while index >= 0:
#如果不是问号则进行下一次循环
if symbolList[index]['symbol'] == '?':
#如果最后两个符号是?:则直接转换
if len(symbolList) == (index + 2):
if symbolList[index + 1]['symbol'] == ':':
#如果这个问号就是第一个符号,则条件从头开始截取
if index == 0:
expressionStr = CaculateOperator.exchangeExpression(expressionStr, 0, symbolList[index]['index'], symbolList[index + 1]['index'], len(expressionStr))
#如果这个问号之前还有符号,则条件从上一个符号之后开始截取
else:
expressionStr = CaculateOperator.exchangeExpression(expressionStr, symbolList[index - 1]['index'] + 1, symbolList[index]['index'], symbolList[index + 1]['index'], len(expressionStr))
symbolList.pop(index + 1)
symbolList.pop(index)
#如果不是最后一组则判断下下项是否为冒号
else:
if symbolList[index + 1]['symbol'] == ':' and symbolList[index + 2]['symbol'] == ':':
#如果这个问号就是第一个符号,则条件从头开始截取
if index == 0:
expressionStr = CaculateOperator.exchangeExpression(expressionStr, 0, symbolList[index]['index'], symbolList[index + 1]['index'], symbolList[index + 2]['index'])
#如果这个问号之前还有符号,则条件从上一个符号之后开始截取
else:
expressionStr = CaculateOperator.exchangeExpression(expressionStr, symbolList[index - 1]['index'] + 1, symbolList[index]['index'], symbolList[index + 1]['index'], symbolList[index + 2]['index'])
symbolList.pop(index + 1)
symbolList.pop(index)
index -= 1
return expressionStr
#根据问号始末、冒号、结尾索引,转换一个三目运算式
@staticmethod
def exchangeExpression(expressionStr, questBeginIndex, questIndex, colonIndex, endIndex):
#拆分条件、两个公式
check = expressionStr[questBeginIndex: questIndex]
checkTrue = expressionStr[questIndex + 1: colonIndex]
checkFalse = expressionStr[colonIndex + 1: endIndex]
#转换
expressionStr = expressionStr[0: questBeginIndex] + '(' + checkTrue + ' if ' + check + ' else ' + checkFalse + ')' + expressionStr[endIndex: len(expressionStr)]
return expressionStr
#替换java转型、数据类型代码为python代码
@staticmethod
def replaceParam(expressionStr):
replace掉应用场景可能出现的各种java代码
return expressionStr
以上,欢迎测试,如果有错请指出