更新宏更新太多

更新宏更新太多

\firstbanner我正在尝试使用 LaTeX 存储和更新三个横幅、、\secondbanner和的值\thirdbanner,使用\addbanner命令进行更新\firstbanner并将旧\firstbanner值放入\secondbanner,将旧值\secondbanner放入\thirdbanner。但是,当我\addbanner使用新值调用时,所有三个横幅最终都具有相同的值。这是我使用的代码:

\newcommand{\thirdbanner}{three}
\newcommand{\secondbanner}{two}
\newcommand{\firstbanner}{one}
\newcommand{\printbanners}{
    Third banner :\thirdbanner \\
    Second banner :\secondbanner \\
    First banner :\firstbanner \\
}
\newcommand{\addbanner}[1]{
    \\ Adding #1: \\ \printbanners \\
    \renewcommand{\thirdbanner}{\secondbanner}
    renew third : \printbanners \\
    \renewcommand{\secondbanner}{\firstbanner}
     renew seconf: \printbanners \\
    \renewcommand{\firstbanner}{hello}
    renew first \printbanners
}

\addbanner{hello}

上面的输出:

LaTeX 输出

答案1

当你这样做时,\renewcommand{\thirdbanner}{\secondbanner}你并没有定义\thirdbanner拥有的当前值\secondbanner,但是你正在定义\thirdbanner扩展为\secondbanner

您需要\secondbanner使用类似以下方式访问的当前值

\expandafter\renewcommand\expandafter\thirdbanner\expandafter{\secondbanner}

或者

\edef\thirdbanner{\unexpanded\expandafter{\secondbanner}}

我建议采用不同的策略:使用一个序列,您可以在其中的任一端添加项目,在本例中是在左侧添加。

\documentclass{article}

\ExplSyntaxOn

\seq_new:N \g_egreg_banner_seq

\NewDocumentCommand{\addbanner}{m}
 {
  \seq_gput_left:Nn \g_egreg_banner_seq { #1 }
 }

\NewExpandableDocumentCommand{\getbanner}{m}
 {
  \seq_item:Nn \g_egreg_banner_seq { #1 }
 }

\ExplSyntaxOff

\newcommand{\printbanners}{%
  Third banner: \getbanner{3}\par
  Second banner: \getbanner{2}\par
  First banner: \getbanner{1}\par
}

\begin{document}

\addbanner{three}
\addbanner{two}
\addbanner{one}

\printbanners

\bigskip

\addbanner{hello}

\printbanners

\bigskip

\addbanner{world}

\printbanners

\end{document}

在此处输入图片描述

作为奖励,您可以访问全部您定义的横幅。


这是一个遗留的实现,但缺点是只保留了前三项。

\documentclass{article}

\makeatletter
% user level commands
\newcommand{\addbanner}[1]{%
  \expandafter\banner@add\expandafter{\banner@container}{#1}%
}
\newcommand{\firstbanner}{%
  \expandafter\banner@first\banner@container\@nil
}
\newcommand{\secondbanner}{%
  \expandafter\banner@second\banner@container\@nil
}
\newcommand{\thirdbanner}{%
  \expandafter\banner@third\banner@container\@nil
}
% internal macros
\newcommand{\banner@container}{{}{}{}}% ensure at least three items
\newcommand\banner@add[2]{\banner@add@aux{#2}#1\@nil}
\def\banner@add@aux#1#2#3#4\@nil{%
  \gdef\banner@container{{#1}{#2}{#3}}%
}
\def\banner@first#1#2#3#4\@nil{#1}
\def\banner@second#1#2#3#4\@nil{#2}
\def\banner@third#1#2#3#4\@nil{#3}
\makeatother

\newcommand{\printbanners}{%
  Third banner: \thirdbanner\par
  Second banner: \secondbanner\par
  First banner: \firstbanner\par
}

\begin{document}

\addbanner{three}
\addbanner{two}
\addbanner{one}

\printbanners

\bigskip

\addbanner{hello}

\printbanners

\bigskip

\addbanner{world}

\printbanners

\end{document}

答案2

欢迎来到宏的“奇妙”世界,它定义“文本”扩展,即替换。

作为初学者,我也习惯使用“常见”编程语言(如 C、C++、C#、Pascal)或脚本语言(如 Python 和 Perl)进行编程。而当第一次接触宏语言时,这种编程语言往往……神秘而出乎意料 :-)。

结果出乎意料,因为人们在做类似的事情时会像在 C 语言中一样以值分配的方式思考

int i = 1; 
int j = i; 
i = 2;

并且人们期望i现在有一个值2,而j有一个值1。定义宏不会将右侧的求值赋给宏,而是将标记列表赋值为替代品到宏。当“调用”宏时,宏标记将被上一个宏定义中有效的标记列表替换。在处理宏时,人们可能会想到“惰性求值”之类的东西,因为在定义宏时,替换文本不会被求值/扩展。

因此之后

\newcommand{\i}{1} 
\newcommand{\j}{\i}
\renewcommand{\i}{2}

这两个宏\i\j具有以下替换标记列表: 在第一个之后\i被替换,最后在之后被替换,而将被替换,之后不会更改,仍然将被替换1\newcommand2\renewcommand\j\i\i不是1正如预期的那样,通过标记列表。

(要查看宏的当前定义,您可以使用原语\show\i\show\j,它将输出指定的替换作为标记列表。如果您使用 TeX GUI,则必须检查日志输出。)

答案3

您需要将一个命令的定义复制到另一个命令中,而不是重新定义它来显示该命令。这通常通过\let或来实现\NewCommandCopy

在此处输入图片描述

\documentclass{article}

\newcommand{\thirdbanner}{three}
\newcommand{\secondbanner}{two}
\newcommand{\firstbanner}{one}
\newcommand{\printbanners}{%
    Third banner: \thirdbanner \\
    Second banner: \secondbanner \\
    First banner: \firstbanner
}
\newcommand{\addbanner}[1]{%
    Adding #1: \\
    \let\thirdbanner\secondbanner
    renew third: \thirdbanner \\
    \let\secondbanner\firstbanner
     renew second: \secondbanner \\
    \renewcommand{\firstbanner}{#1}%
    renew first: \firstbanner
}

\setlength{\parindent}{0pt}% Just for this example

\begin{document}

\printbanners

\bigskip

\addbanner{how}

\medskip

\addbanner{now}

\medskip

\addbanner{brown}

\medskip

\addbanner{cow}

\end{document}

相关内容