创建一个“切换”宏,根据命令的参数更新命令

创建一个“切换”宏,根据命令的参数更新命令

我想知道为什么这不能编译:

\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}

相关内容