在 luatex 中将宏作为字符串传递

在 luatex 中将宏作为字符串传递

在 lua 中我有一个名为“simpFracs”的函数,它接受一个字符串和一个名为“simpFracs”的数字(它应该接受一个分数和一个数字,将它们相乘,返回一个数字)

我有一个非常恶心的宏(这是一个显示数学问题的工作步骤的宏)

\def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}

例如,#1=10 和 #2=8 会扩展为

\frac{1}{4}

对于 LuaLatex,我想将 xval 作为字符串传递。宏如下所示:

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

simpFracs 宏可以很好地处理如下字符串

\simpFracs{\frac{1}{4}}{\frac{4}{1}}

工作正常,但是当我添加宏时,我不知道如何让它工作......

\simpFracs{\xval}{\\frac{4}{1}}

我已经尝试查找宏扩展几个小时了,但我不知道它们如何在字符串中扩展

完整的工作示例:(我省略了这一点,因为它太恶心了)

-- in math.lua
-- I am aware this code is bad, but it works, its an assignment, I dont care if its hacky

function simpfrac(a,b)     
    sign = false;
    if a < 0 then
        sign = true
    end
    if b < 0 then
        if sign == true then
            sign = false
        else
            sign = true
        end
    end

    a = math.abs(a)
    b = math.abs(b)

    local function gcd(a,b)   
        if b ~= 0 then
            return gcd(b, a % b)
        else
            return math.abs(a)
        end
    end

    t = gcd(a, b)
    if b/t == 1 then
        if sign == true then
         tex.sprint(-math.floor(a/t))
        else
            tex.sprint(math.floor(a/t))
        end
        
    else
        -- Floor removes the decimal points
        if sign == true then
            tex.sprint("-\\frac{", math.floor(a/t), "}{", math.floor(b/t), "}")
        else
            tex.sprint("\\frac{", math.floor(a/t), "}{", math.floor(b/t), "}")
        end
    end  
end    

function simpmult(a,b)
        tex.sprint(a*b)
end

-- a = string (frac), b = string(frac)
function simpfracs(a,b)
    -- Parse frac
    -- frac{a} {b}
    local fraca = {}
    local fracb = {}
    for w in string.gmatch(a, "{([^{}]*)}") do
        table.insert(fraca,w)
    end
    for w in string.gmatch(b, "{([^{}]*)}") do
        table.insert(fracb,w)
    end
    c = fraca[1]/fraca[2]
    d = fracb[1]/fracb[2]
    tex.sprint(math.floor(c*d))
end

任意名称.tex

\documentclass[10pt,a4paper]{article}

\directlua{dofile("math.lua")}
\newcommand{\simpFrac}[2]{%
  \directlua{simpfrac(#1,#2)}%
}
\newcommand{\simpMult}[2]{%
  \directlua{simpmult(#1,#2)}%
}
\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

\begin{document}

\newcommand{\surgefiw}[2]{
    \def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}
    $x = \xval$ \\
    $f(x) = #1xe^{-#2x}$ \\
    % Want it to be this (But without the \\frac{1}{4} hard coded)
    $y=\simpFracs{\\frac{1}{4}}{\\frac{#1}{1}}e^{\simpFracs{\\frac{1}{4}}{\\frac{-#2}{1}}}$ \\ 
    % Dont know how to make this compile
    %$y = \simpFracs{\xval}{\frac{#1}{1}}e^{\simpFracs{\xval}{\frac{-#2}{1}}}$ \\
}

\surgefiw{10}{8}

\end{document}

更新:想出了如何修复反斜杠问题,我只需要改变

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("#1","#2")}%
}

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

但是现在从宏传递的参数是:"\protect {\begingroup 1\endgroup \over 4}"and"\protect {\begingroup 10\endgroup \over 1}"而不是"\frac{1}{4}"and"\frac{10}{1}"和我不知道如何去修复它......

答案1

在最初发现必须转换后

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("#1","#2")}%
}

\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

我意识到它需要两种输入类型中的一种,因此我没有尝试理解 latex,而是使用 lua 来解析它们。
输入可能是\frac{a}{b}\protect {\begingroup a\endgroup \over b}
为了保持代码的可读性,我将其拆分为函数,这意味着我还必须解析常量。最后留下的是 lua 代码:

function parsefrac(a)
    print("A is", a)
    -- First check is input is constant (Format 1)
    local consta = {}
    for w in string.gmatch(a, "%d+") do
        table.insert(consta,w)
    end
    if consta[2] == nil then
        print("String is format 1!")
        b = consta[1]
        return b;
    end

    
    -- frac{a}{b} -- (Format 2)
    if a.sub(a,1,string.len("\\frac")) == "\\frac" then
        -- Format 1
        print("String is format 2!")
        local fraca = {}
        
        for w in string.gmatch(a, "{([^{}]*)}") do
            table.insert(fraca,w)
        end
        
        b = fraca[1]/fraca[2]
        
        return b
        
    else
        -- \protect {\begingroup a\endgroup \over b} -- (Format 3)
        print("String is format 3!")
        local fraca = {}
        for w in string.gmatch(a, "%d+") do
            table.insert(fraca,w)
        end
        b = fraca[1]/fraca[2]
        
        return b
    end
end

-- a = string (frac), b = string(frac)
function simpfracs(a,b)
    -- Parse typesetting
    
    c = parsefrac(a)
    d = parsefrac(b)
    
    tex.sprint(math.floor(c*d))
end

给定输入

\documentclass[10pt,a4paper]{article}

\directlua{dofile("math.lua")}
\newcommand{\simpFrac}[2]{%
  \directlua{simpfrac(#1,#2)}%
}
\newcommand{\simpMult}[2]{%
  \directlua{simpmult(#1,#2)}%
}
\newcommand{\simpFracs}[2]{%
  \directlua{simpfracs("\luaescapestring{#1}","\luaescapestring{#2}")}%
}

\begin{document}

\newcommand{\surgefiw}[2]{
    \def\xval{\simpFrac{1}{\simpFrac{\simpMult{-\simpMult{#1}{#2}}{-#2}}{\simpMult{\simpMult{#1}{#2}}{2}}}}
    $x = \xval$ \\
    $f(x) = #1xe^{-#2x}$ \\
    $y = \simpFracs{\xval}{\frac{#1}{1}}e^{\simpFracs{\xval}{\frac{-#2}{1}}}$ \\
}

\surgefiw{10}{8}

\end{document}

将产生所需的结果。
这不在原始问题的范围之内,但为了完整性,我知道 1/4 * 10 = 2 中存在逻辑错误,但已通过更改来修复

tex.sprint(math.floor(c*d))

    if c*d == math.floor(c*d) then
        tex.sprint(math.floor(c*d))
    else
        simpfrac(c*d,1)
    end

在 simpfracs 函数的末尾

相关内容