在Corona Lua中评估数学字符串

我想在我的 corona 应用程序中评估一个数学字符串。目前我正在重点关注三角函数,所以我们让这个例子变得最困难:

local expr = "2sin(4pi+2)+7"

我的目标是让它以某种方式被评估(或者)就像一个 pi --> math.pi 开关,即使分解也可以。分解会更加困难,因为它可能像上面那样复杂,也可能只是 sin(1)

所以我更喜欢尽可能接近 python 的 eval(expr) 函数,但如果不能实现,我也可以接受其他方法。

点赞
用户1442917
用户1442917

最简单的方法是将 sin 替换为 math.sinpi 替换为 math.pi等),添加丢失的乘法符号,然后将其通过 loadstring 运行,但是在 Corona 环境中无法使用 loadstring

这意味着您需要为这些表达式编写自己的解析器。我在 Corona 论坛上找到了一场讨论,可能会帮助您作为起点:这里,并提供了一些细节和演示 这里

2012-09-24 15:44:20
用户4581102
用户4581102

这应该能解决问题,能够使用lua数学函数而不需要使用'math.function',所以sqrt(100)就可以正常工作。我把这个东西放在一起,因为我看到这个问题被问了太多次了。希望能帮到你 :)

如果你有任何问题,随时联系我rayaman99@gmail.com

function evaluate(cmd,v) -- 这个使用递归来解决数学方程式
    --[[ 我们把它分成几个部分、每次解决小的部分然后把它们合在一起
        下面是一个例子
        假设我们有一个 "5+5+5+5+5"
        首先我们得到这个:
        5+5+5+5 +   5
        5+5+5   +   5
        5+5 +   5
        5   +   5
        取所有的单独的5并且把它们的运算,这个情况下是加起来,得到25
        如果你想用一个自定义的表达式来直观地看到这一点,请取消下面的代码 '--print(l,o,r)'
    ]]
    v=v or 0
    local count=0
    local function helper(o,v,r)-- 一个本地的帮助函数来加速并使代码更小
        if type(v)=="string" then
            if v:find("%D") then
                v=tonumber(math[v]) or tonumber(_G[v]) -- 这一部分允许使用全局变量和来自数学的变量,请随意添加你自己的环境
            end
        end
        if type(r)=="string" then
            if r:find("%D") then
                r=tonumber(math[r]) or tonumber(_G[r]) -- 上面的一个镜像,这个作用于方程式的另一边
                -- 想一想,和 '5+a' 和 'a+5'。这个镜像允许我攻击表达式的两边
            end
        end
        local r=tonumber(r) or 0
        if o=="+" then -- 在这里处理不同的数学运算符号
            return r+v
        elseif o=="-" then
            return r-v
        elseif o=="/" then
            return r/v
        elseif o=="*" then
            return r*v
        elseif o=="^" then
            return r^v
        end
    end
    for i,v in pairs(math) do
        cmd=cmd:gsub(i.."(%b())",function(a)
            a=a:sub(2,-2)
            if a:sub(1,1)=="-" then
                a="0"..a
            end
            return v(evaluate(a))
        end)
    end
    cmd=cmd:gsub("%b()",function(a)
        return evaluate(a:sub(2,-2))
    end)
    for l,o,r in cmd:gmatch("(.*)([%+%^%-%*/])(.*)") do -- 迭代,这将表达式拆成几个部分,当添加到其中时,它们变得更易于管理
        --print(":",l,o,r) -- 取消注释以查看它是如何工作的
        count=count+1 -- 记录一些特定条件
        if l:find("[%+%^%-%*/]") then -- 如果我发现表达式的左边包含让我们继续拆分的东西
            v=helper(o,r,evaluate(l,v))-- 再次计算并进行帮助函数
        else
            if count==1 then
                v=helper(o,r,l) -- 这是包含一个数字符号的情况
            end
        end
    end
    if count==0 then return (tonumber(cmd) or tonumber(math[cmd]) or tonumber(_G[cmd])) end
    -- 你也可以添加自己的环境...我使用math和_G
    return v
end
a=5
print(evaluate("2+2+2*2")) -- 这还有一些工作要做,当它涉及到pemdas的时候;然而,使用括号可以有序地排列事物!
print(evaluate("2+2+(2*2)"))-- <-- 正如这里所看到的
print(evaluate("sqrt(100)"))
print(evaluate("sqrt(100)+abs(-100)"))
print(evaluate("sqrt(100+44)"))
print(evaluate("sqrt(100+44)/2"))
print(evaluate("5^2"))
print(evaluate("a")) -- 我们上面储存的
print(evaluate("pi")) -- math.pi
print(evaluate("pi*2")) -- math.pi
2016-10-30 21:30:57