我在想菲利克斯的问题,他想在其中返回列表TikZ
。到目前为止,我的方法是将单个结果作为单独的返回\nodes
,每个结果相隔一厘米。现在我想知道是否有办法在循环的每次迭代中将一些文本附加到变量(或命令或宏或其他任何东西)中\foreach
。我试过这个:
\documentclass{scrartcl}
\usepackage{tikz}
\newcommand{\myresult}{}
\newcommand{\longertext}[1]%
{ \foreach \x in {1,2,...,#1}
{ \renewcommand{\myresult}{blah \myresult}
}
}
\begin{document}
Start
\longertext{5}
\myresult
Stop
\end{document}
我认为这就像 Pascal 中的一样:
s:='';
for i:=1 to 5 do begin
s:='blah '+s;
end;
所以基本上我认为我的代码应该执行以下操作:
- 创建一个空变量
myresult
- 对于循环的每次迭代,在开头附加“blah”
- 因此,呼叫后
\longertext{5}
,\myresult
应按住“blah blah blah blah blah”
但当我运行它时,\myresult
它显示为空。有人能解释一下原因吗,并能提供解决方案吗?
答案1
解释起来需要一点 TeX 理论。
A团体是文档的一部分,它将其中所做的大多数更改仅限于该组本身。也就是说,组内更改的大多数设置在组结束后将恢复为旧值。组以{ … }
或分隔\begingroup … \endgroup
。例如,某条命令\itshape
将字体形状切换为斜体。如果在文档中使用它,则该点之后的所有文本都将设置为斜体(除非另一个命令再次切换字体)。但如果在组内使用 — {\itshape test}
— ,其效果只会持续到组结束;当组结束时,字体将恢复为组启动之前的状态。如果分配或宏定义应该超越它所在的任何组,并在组结束后仍然有效,则必须以 为前缀\global
(这仅适用于原始 TeX 操作)。
用替换文本替换宏称为扩展宏。TeX 在读取输入时会扩展宏,但它不一定扩展命令的参数——它们会按原样传递。因此,在
\def\a{a}
\def\b{b \a}
(\def
是定义新宏的 TeX 基元), 的替换文本\b
是b \a
,而不是b a
。只有当 时\b
,才会递归扩展。如果在定义时\a
需要,则存在一个类似的基元— ,它会完全(即递归)扩展要替换的文本,然后将文本与宏名称关联起来。\a
\b
\def
\edef
现在让我们看一下代码。
虽然无法直接看到,但 中的迭代代码\foreach
是在一个组内处理的。因此, 的结果\renewcommand
在每次迭代后都会被立即遗忘,最终\myresult
仍为空。我们可以通过使用\global\def
而不是 来解决这个问题\renewcommand
(\renewcommand
是一个复杂的宏,不会受到 的影响\global
):
\global\def\myresult{blah \myresult}
但现在我们遇到了一个不同的问题。至少经过一次迭代后,\myresult
现在有替换文本blah \myresult
。如果 TeX\myresult
在输入中遇到,它将用 替换宏blah \myresult
,然后用 替换blah blah \myresult
,……直到没有剩余内存。问题是我们通过定义一个扩展为自身的宏导致了无限递归。我们想在\myresult
重新定义它时使用 的旧值,但最终使用了宏本身。我们已经知道我们可以使用\edef
而不是\def
来做前者而不是后者。现在相关的行变成
\global\edef\myresult{blah \myresult}
Plain TeX 定义\xdef
为\global\edef
。所以我们可以缩短代码:
\xdef\myresult{blah \myresult}
现在它将按计划运行。
解释完这些之后,包etoolbox
提供命令\xpreto<hook>{<code>}
和\xappto<hook>{<code>}
,它们将全局地将的扩展添加code
到的定义中<hook>
。我还应该注意,空格和换行符对 TeX 和代码来说很重要需要一些注释字符。
答案2
\foreach
在作用域内运行命令,因此更改的宏在循环外不可用。您可以做的是使用命令\global
使赋值在作用域外可用,并使用\edef
而不是\renewcommand
在再次赋值之前扩展旧宏。此外,您不需要使用{1,2,...,#1}
来指示一步,而是可以直接说{1,...,#1}
。这也允许宏用于单次重复(在这种情况下没有多大意义)。
编辑: \myresult
正如 Tom Bombadil 指出的那样,应该首先设置为宏{}
内部。\longertext
\documentclass{article}
\usepackage{tikz}
\newcommand{\longertext}[1]%
{%
\gdef\myresult{} %
\foreach \x in {1,...,#1}%
{%
\global\edef\myresult{blah \myresult}%
}%
}
\begin{document}
Start
\longertext{5}
\myresult
\longertext{3}
\myresult
Stop
\end{document}