我正在尝试\multiboxed
在 LaTeX 中定义一个新命令,以便我可以输入n围绕方程式添加框,而无需手动嵌套\boxed
命令。到目前为止,我已经(使用pgffor
包):
def\multiboxed#1#2{
\foreach \index in {1, ..., #1} {
Hello
}
#1
\foreach \index in {1, ..., #1} {
World
}
}
成功用 和 包装第二个参数Hello
,World
次数与第一个参数相同。但是,将其更改为
def\multiboxed#1#2{
\foreach \index in {1, ..., #1} {
\fbox{
}
#1
\foreach \index in {1, ..., #1} {
}
}
}
确实不起作用,正如预期的那样。因此,我有两个问题,我只需要回答其中一个:
- 如何成功修改 for 循环以实现所需的行为?
- 或者,我如何定义递归命令来实现相同的输出?
显然,对 (2) 的回答会更好,因为这是解决问题的更好方法,但我觉得我最好理解对 (1) 的回答。理想情况下,我也不必依赖该pgffor
软件包。感谢您对此事的任何见解。
答案1
到目前为止的答案都没有问题,但它们都使用了重量级的大型包,而这个版本根本不使用任何包,并且需要的代码更少。
\documentclass{article}
\def\Fbox#1#2{\ifnum#1=0\mbox{#2}\else\fbox{\Fbox{\numexpr#1-1\relax}{#2}}\fi}
\begin{document}
\Fbox{0}{hello}
\Fbox{1}{hello}
\Fbox{2}{hello}
\Fbox{3}{hello}
\Fbox{4}{hello}
\Fbox{5}{hello}
\end{document}
另一种变体使用\@first/@secondoftwo
:
\makeatletter
\def\Fbox#1#2{%
\ifnum#1=0\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\mbox{#2}}{\fbox{\Fbox{\numexpr#1-1\relax}{#2}}}%
}
\makeatother
答案2
令牌寄存器可以收集嵌套的\fbox
命令。\global
是必要的,因为的主体\foreach
是成组执行的。
\documentclass{article}
\usepackage{pgffor}
\newtoks\ToksMultiBoxed
\newcommand*{\multiboxed}[2]{%
\global\ToksMultiBoxed{#2}%
\ifnum#1>0 %
\foreach \index in {1,...,#1} {%
\global\ToksMultiBoxed\expandafter{%
\expandafter\fbox\expandafter{\the\ToksMultiBoxed}%
}%
}%
\fi
\the\ToksMultiBoxed
}
\begin{document}
\multiboxed{4}{Hello}
\multiboxed{1}{World}
\multiboxed{0}{!}
\end{document}
\documentclass{article}
\usepackage{loops}[2012/10/16]
\makeatletter
\newcommand*{\multiboxed}[2]{%
\skvifnumTF#1=\z@{%
#2%
}{%
\@temptokena{#2}%
\foreachfox {1,...,#1} {%
\skvexpanded{\@temptokena{\noexpand\fbox{\the\@temptokena}}}%
}%
\the\@temptokena
}%
}
\makeatother
\begin{document}
\multiboxed{4}{Hello}
\multiboxed{1}{World}
\multiboxed{0}{!}
\end{document}
答案3
正如 David Carlisle 所说,其他答案并没有错。也就是说,只要你满足于清楚的盒子。但是说到画盒子,没有什么比这个tikz
方法更好了:
通过在两个框中使用白线来实现额外的间距。
代码:
\documentclass{article}
\usepackage{tikz}
\usepackage{xstring}
\tikzset{Dotted Red/.style={draw=red, dotted, line width=1pt}}
\tikzset{Dashed Violet/.style={draw=violet, dashed}}
\newcommand{\Boxed}[3][]{
\begin{tikzpicture}[baseline, inner sep=0, outer sep=0]
\node [thick] (Origin) {#3};
\foreach \x in {1,...,#2} {%
\pgfmathsetmacro{\Shift}{0.1*(\x+1)}%
\StrBetween[\x,\numexpr\x+1\relax]{,#1,}{,}{,}[\LineStyle]
\draw [thick, draw=black, \LineStyle]
([shift={(-\Shift cm,-\Shift cm)}]Origin.south west) rectangle
([shift={( \Shift cm, \Shift cm)}]Origin.north east) ;
}%
\end{tikzpicture}
}
\begin{document}
\Boxed{3}{Hello}
\hspace{1cm}
\Boxed[blue,black,green,violet,red]{5}{Hello World}
\bigskip
\hspace{1.0cm}\Boxed[blue,black,white,white,Dashed Violet,Dotted Red]{6}{How you doin?}
\end{document}
答案4
xparse
以下是使用和的实现expl3
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\multibox}{mm}
{
\multibox_do:nn { #1 } { #2 }
}
\tl_new:N \l_multibox_tokens_tl
\cs_new_protected:Npn \multibox_do:nn #1 #2
{
\tl_set:Nn \l_multibox_tokens_tl { #2 }
\prg_replicate:nn { #1 }
{
\tl_set:Nx \l_multibox_tokens_tl { \exp_not:N \fbox{ \exp_not:V \l_multibox_tokens_tl } }
}
\tl_use:N \l_multibox_tokens_tl
}
\ExplSyntaxOff
\begin{document}
\multibox{5}{Hello}
\multibox{2}{world}
\end{document}
它表现出一个有趣的特点:在复制的每一步中,先前的内容\l_multibox_tokens_tl
仅扩展一次,即使在“完全扩展”的上下文中也是如此。
让我们看看它是如何工作的。正如样式指南所建议的那样,用户级命令\multibox
被转换为函数,因此第一个定义并不神秘。
接下来,我们保留一个标记列表变量,该变量将设置为我们要装箱的文本。完成此分配后,我们启动一个简单的循环,其中使用 重复一些代码\prg_replicate:nn{...}{...}
。第一个参数是重复次数,第二个参数是代码。
这是重要的部分:每次都会重置令牌列表变量:
\tl_set:Nx \l_multibox_tokens_tl { <tokens> }
完全展开<tokens>
并将结果存储在标记列表变量中。但是,这种“完全展开”是可以控制的:在这种情况下,我们传递
\exp_not:N \fbox{ \exp_not:V \l_multibox_tokens_tl }
这意味着将按\fbox
原样存储(即“\noexpand”);左括号已经像右括号一样不可展开。现在
\exp_not:V \l_multibox_tokens_tl
传递变量的当前值,但不会再扩展。因此\l_multibox_tokens_tl
执行过程中的连续值\multibox{5}{Hello}
将是
Hello
\fbox{Hello}
\fbox{\fbox{Hello}}
\fbox{\fbox{\fbox{Hello}}}
\fbox{\fbox{\fbox{\fbox{Hello}}}}
\fbox{\fbox{\fbox{\fbox{\fbox{Hello}}}}}
并且这个最后的值最终被传送用于排版。
因此,它与 Heiko 的第一个解决方案(使用令牌寄存器和)并没有太大区别\edef
。