![在 luatex 中将宏作为字符串传递](https://linux22.com/image/417662/%E5%9C%A8%20luatex%20%E4%B8%AD%E5%B0%86%E5%AE%8F%E4%BD%9C%E4%B8%BA%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%BC%A0%E9%80%92.png)
在 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 函数的末尾