我想知道为什么这不能编译:
\documentclass{article}
\newcommand{\testbasic}{BASIC}
\newcommand{\testfirst}{FIRST}
\newcommand{\testsecond}{SECOND}
\newcommand{\test}{\testbasic}
\newcommand{\switch}[1]{
\directlua{
tex.sprint([[\noexpand\renewcommand{\noexpand\test}{\noexpand\test#1}]])
}
}
\begin{document}
\test
\switch{first}
\test
\switch{second}
\test
\switch{basic}
\test
\end{document}
错误是:
! TeX capacity exceeded, sorry [input stack size=5000].
\test ->\test
first
l.20 \test
因此显然 lua 输出符合\renewcommand{\test}{\test}
我的预期\renewcommand{\test}{\testfirst}
难道不tex.sprint
应该处理这样的案件吗?
我的情况有解决办法吗?
有没有更好的方法来实现它,使用或不使用 lua?
附加问题:我可以避免所有这些\noexpand
以生成更清晰的代码吗?
答案1
你基本上做的是
\newcommand\switch[1]{\renewcommand{\test}{\test#1}}
这当然行不通,因为\test
它本身就是一个 token,所以当你这样做时,\switch{first}
效果是
\renewcommand{\test}{\test first}
\test
当展开时当然会产生无限循环。
\documentclass{article}
\newcommand{\testbasic}{BASIC}
\newcommand{\testfirst}{FIRST}
\newcommand{\testsecond}{SECOND}
\newcommand{\test}{\testbasic}
\newcommand{\switch}[1]{%
\directlua{
tex.sprint([[\noexpand\renewcommand{\noexpand\test}{\expandafter\noexpand\csname test#1\endcsname}]])
}%
}
\begin{document}
\test
\switch{first}
\test
\switch{second}
\test
\switch{basic}
\test
\end{document}
您可以使用以下方法获得相同的结果expl3
:
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_protected:Npn \switch #1
{
\cs_set:Npx \test { \exp_not:c {test#1} }
}
\ExplSyntaxOff
\newcommand{\testbasic}{BASIC}
\newcommand{\testfirst}{FIRST}
\newcommand{\testsecond}{SECOND}
\newcommand{\test}{\testbasic}
\begin{document}
\test
\switch{first}
\test
\switch{second}
\test
\switch{basic}
\test
\end{document}