将python自动翻译成js脚本
说明
由于想用通过写python代码直接翻译出来对应的js代码,python代码有它自身的简洁性,代码量比较少,可以做一个脚本翻译成运行速度高但是代码量打的编程语言,由于js相对java来说更加接近动态脚本语言的特性,所以先做了python翻译成js的方法。
翻译的不能保证能够正常运行,但是反正总比手动改方便多了。起码括号自动加上了,结构上都符合js的标准了。
以后可能还会打算做自动类型检测和推断,然后做出python翻译成java或者C++,这可能有助于做一些算法题。
展示
可以用while循环来做成实时翻译,一边写代码,一边运行脚本,一边实时更新翻译出来的结果
左侧是python代码,右侧是实时翻译成的js代码
主要思路
- 清除函数注解
- 根据缩进添加大括号结构
- 增加赋值语句的 let 关键字
- 进行一些关键字和函数名的简单替换
- 处理主程序入口翻译
- 多行注释的语法转化
- 模板字符串的翻译
f"{}" 换成 " ${} " (ES6的反引号) - 添加分号
源代码
说明:直接调用trans函数,输入python代码字符串,返回的是翻译后的js代码字符串。
"""
将python代码转化成js代码的主程序
2021年12月08日
by littlefean
"""
import os
from time import sleep
def main():
while True:
os.system("cls")
with open(f"..\\in\\py4.py", encoding="utf-8") as f:
content = f.read()
print(trans(content))
sleep(0.5)
return None
def trans(inputString: str) -> str:
"""
:param inputString: python代码字符串
:return: js代码字符串
"""
res = inputString
res = clearFuncNote(res)
res = changeContainerCode(res)
res = addLet(res)
res = simpleReplace(res)
res = mainScript(res)
res = changeMulLineCommonCode(res)
res = templeStrTrans(res)
res = addSemicolon(res)
return res
def iterCode(lineStr: str) -> str:
"""对循环条件表达式的处理
<i in range(n)> let i = 0; i < n; i++
<nChild in self.graphDic[n]>
<nChild == n>
<mChild in self.graphDic[m]>
<mChild == m>
<n in self.graphDic[m]>
<k, v in self.graphDic.items()>
<meeting in meetings>
<time not in timeDic>
<time, connectList in timeDic.items()>
<con in connectList>
<know in knows>"""
words = lineStr.split()
wordCount = len(words)
res = lineStr
if wordCount == 3:
if "in" in lineStr and "range(" in lineStr:
parInner = getParInner(lineStr)
parInnerArr = parInner.split(",")
if len(parInnerArr) == 1:
return f"let {words[0]} = 0; {words[0]} < {parInner}; {words[0]}++"
elif len(parInnerArr) == 2:
...
else:
return f"let {words[0]} = 0; {words[0]} < {parInner}; {words[0]}++"
elif "in" in lineStr and "range(" not in lineStr:
return f"let {words[0]} of {words[2]}"
return res
def changeContainerCode(res: str) -> str:
"""将将 `xx(...) {` 类型语句替换
注意:这个操作会更改代码的行数,会插入一些行"""
lineArr = res.split("\n")
lineNum = len(lineArr)
""" 额外加小括号类型
while a == b:
while (a == b) {
if a == b:
if (a == b) {
"""
words = ["while", "for", "if", "elif"]
""" 直接替换类型
class Main:
class Main {
def does():
function does() {
else:
else {
"""
words2 = ["class", "def", "else"]
for i, line in enumerate(lineArr):
if i == lineNum - 1:
break
firstWord = getFirstWord(line)
if (firstWord in words or firstWord in words2) and line.strip().endswith(":"):
tabs = getLeftCount(line, " ")
for j in range(i + 1, lineNum):
if lineArr[j].strip() == "":
if j + 1 == lineNum:
lineArr[j] = "}"
else:
continue
elif getLeftCount(lineArr[j], " ") <= tabs:
lineArr[j - 1] = lineArr[j - 1] + f"\n{tabs * ' '}" + "}"
break
if firstWord in words:
left = lineArr[i].find(firstWord) + 1
eqCode = lineArr[i][left + len(firstWord):-1]
lineArr[i] = lineArr[i][:left + len(firstWord)] + f"({iterCode(eqCode)})" + " {"
lineArr[i] = lineArr[i].replace(":", " {")
elif firstWord in words2:
lineArr[i] = lineArr[i].replace(":", " {")
return "\n".join(lineArr)
def addSemicolon(pyStr: str) -> str:
"""添加分号"""
lineArr = pyStr.split("\n")
def doNotNeed(lineStr: str):
lineStrip = lineStr.strip()
for string in ["", "/**", "*/", ":"]:
if string == lineStrip:
return True
endCode = "{}[("
for char in endCode:
if lineStr.strip().endswith(char):
return True
return False
for i, line in enumerate(lineArr):
if doNotNeed(line):
continue
lineArr[i] = lineArr[i] + ";"
...
return "\n".join(lineArr)
def changeMulLineCommonCode(pyStr: str) -> str:
"""将多行注释转化成C风格类型的多行注释"""
lineArr = pyStr.split("\n")
numArr = [0] * len(lineArr)
n = 1
for i, line in enumerate(lineArr):
stripLine = line.strip()
if stripLine.startswith('"""') and stripLine.endswith('"""') and len(stripLine) > 3:
lineArr[i] = line.replace('"""', "")
spaceN = getLeftCount(lineArr[i], " ")
lineArr[i] = lineArr[i][:spaceN] + "// " + lineArr[i][spaceN:]
elif stripLine.startswith("'''") and stripLine.endswith("'''") and len(stripLine) > 3:
lineArr[i] = line.replace("'''", "")
spaceN = getLeftCount(lineArr[i], " ")
lineArr[i] = lineArr[i][:spaceN] + "// " + lineArr[i][spaceN:]
elif stripLine.startswith('"""'):
numArr[i] = n
n += 1
elif stripLine.endswith('"""'):
numArr[i] = n
n += 1
for i, num in enumerate(numArr):
if num != 0:
if num % 2 == 1:
lineArr[i] = lineArr[i].replace('"""', "/**")
for j in range(i + 1, len(numArr)):
if numArr[j] != 0:
break
spaceN = getLeftCount(lineArr[i], " ")
lineArr[j] = lineArr[j][:spaceN] + " * " + lineArr[j][spaceN:]
else:
lineArr[i] = lineArr[i].replace('"""', " */")
return "\n".join(lineArr)
def templeStrTrans(pyStr: str) -> str:
"""进行模板字符串处理"""
def tempLineTrans(lineStr: str) -> str:
"""
print(f"{1+2}")
print(`${1+2}`)
缺陷:目前一行上只能处理一个
:param lineStr:
:return:
"""
if "f\"" in lineStr:
index = lineStr.find("f\"")
newLine = lineStr[:index]
newLine += "`"
isIn = True
for j in range(index + 2, len(lineStr)):
if lineStr[j] == "{" and isIn:
newLine += "$"
if lineStr[j] == "\"":
isIn = False
newLine += "`"
continue
newLine += lineStr[j]
return newLine
return lineStr
lineArr = pyStr.split("\n")
for i, line in enumerate(lineArr):
lineArr[i] = tempLineTrans(line)
...
return "\n".join(lineArr)
def clearFuncNote(pyStr: str) -> str:
"""清除函数注解"""
lineArr = pyStr.split("\n")
for i, line in enumerate(lineArr):
if line.strip().startswith("def"):
if "->" in line:
line = line[:line.find("->")] + ":"
left = line.find("(")
right = line.rfind(")")
midCode = line[left + 1: right]
midArr = midCode.split(",")
newMidArr = []
for arg in midArr:
if ":" in arg:
newMidArr.append(arg[:arg.find(":")])
midCode = ",".join(newMidArr)
lineArr[i] = line[:left + 1] + midCode + line[right:]
...
return "\n".join(lineArr)
def mainScript(pyStr: str) -> str:
"""处理程序入口"""
lineArr = pyStr.split("\n")
find = False
findLine = 0
for i, line in enumerate(lineArr):
if "if" in line and "__name__" in line and "__main__" in line:
lineArr[i] = 'window.onload = function() {'
find = True
findLine = i
if find:
for i in range(findLine, len(lineArr)):
if lineArr[i] == "":
lineArr[i] = "}"
return "\n".join(lineArr)
def addLet(pyStr: str) -> str:
"""添加变量声明let语句"""
lineArr = pyStr.split("\n")
for i in range(len(lineArr)):
if isSetValueLine(lineArr[i]):
lineArr[i] = setValue(lineArr[i])
return "\n".join(lineArr)
def simpleReplace(pyStr: str) -> str:
"""简单替换"""
res = pyStr
replaceDic = {
"def ": "function ",
"None": "null",
"#": "//",
"print(": "console.log(",
"input(": "prompt(",
"elif": "else if",
"abs(": "Math.abs(",
"int(": "parseInt(",
".append(": ".push(",
" and ": " && ",
" or ": " || ",
"...": "pass",
" not ": " ! ",
" == ": " === ",
"True": "true",
"False": "false",
"self.": "this.",
"function __init__": "constructor",
"def __init__(": "constructor",
"(self)": "()",
"(self,": "(",
".pop(0)": ".shift()",
"__str__": "toString",
}
for k, v in replaceDic.items():
res = res.replace(k, v)
return res
def isPrintLine(line: str) -> bool:
"""判断这一行是否是打印行"""
return "print(" in line
def isCommonLine(line: str) -> bool:
"""判断这一行是否是注释行
传入的是python字符串"""
return " #" in line
def isSetValueLine(word: str) -> bool:
"""判断一行是否是变量赋值行"""
words = [
"print",
"console.log",
"while",
"for",
"elif",
"else if",
]
if " = " in word:
for keyWord in words:
if keyWord in word:
return False
return True
else:
return False
def setValue(pyStr: str) -> str:
"""把一个python赋值语句转化成js的"""
spaceN = getLeftCount(pyStr, " ")
res = pyStr[:spaceN] + "let " + pyStr[spaceN:]
return res
def getFirstWord(lineStr: str) -> str:
"""获取这个行代码的第一个关键字, 如果没有关键字就返回空字符串"""
res = ""
strip = lineStr.strip()
if len(strip) == 0:
return ""
if strip[0].isalpha():
for char in strip:
if char.isalpha():
res += char
else:
break
return res
def getLeftCount(string: str, char: str) -> int:
"""获取一个字符串左侧有多少个字符"""
res = 0
for c in string:
if c == char:
res += 1
else:
break
return res
def getParInner(line: str) -> str:
"""获取一行中第一次发现括号中最外层括号里面内容
for i in range(100) 100
for i in range(len(arr)) len(arr)
"""
res = ""
find = False
stackN = 0
for char in line:
if char == "(" and not find:
find = True
stackN += 1
continue
if find:
if char == "(":
stackN += 1
if char == ")":
stackN -= 1
if stackN <= 0:
return res
res += char
...
return res
def test():
print(getParInner("for i in range(1324):"))
print(getParInner("for i in range(len(arr)):"))
print(getParInner("for i in range(len(en(111), ())):"))
...
if __name__ == "__main__":
main()
|