如何连接字符串,例如创建返回列表的命令?

如何连接字符串,例如创建返回列表的命令?

我在想菲利克斯的问题,他想在其中返回列表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 基元), 的替换文本\bb \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}

相关内容