java-python三目运算转换

一 三目运算

    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
以上,欢迎测试,如果有错请指出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值