我正在尝试编写一个\multicenter
宏,它的作用类似于\centerline
,只不过每当它遇到命令 时,它都会将文本拆分成不同的行\\
。例如, \multicenter{ciao\\a\\tutti!}
应该相当于\centerline{ciao}\centerline{a}\centerline{tutti!}
。
我想出了以下代码:
\def\multicenter#1{\def\\{\egroup\centerline\bgroup}\centerline{#1}}
但它并没有像预期的那样工作。发生了什么?
答案1
\centerline
是一个带有一个参数的宏;您可以使用“扩展”定义\line
(即\hbox to \hsize
):
\def\multicenter#1{%
\par
\bgroup % keep changes local
\def\\{\hss\egroup\line\bgroup\hss}%
\line{\hss#1\hss}%
\egroup
}
\centerline{ciao}
\centerline{a}
\centerline{tutti}
\multicenter{ciao\\a\\tutti}
\bye
还允许周围有空格\\
:
\def\multicenter#1{%
\par
\bgroup % keep changes local
\def\\{\unskip\hss\egroup\line\bgroup\hss\ignorespaces}%
\line{\hss#1\hss}%
\egroup
}
\centerline{ciao}
\centerline{a}
\centerline{tutti}
\multicenter{ciao \\ a \\ tutti}
\bye
你的宏会发生什么?让我们尝试更简单的\multicenter{ciao\\mondo}
,它变成
\def\\{\egroup\centerline\bgroup}\centerline{ciao\\mondo}}
定义被存储并\centerline
根据进行扩展\def\centerline#1{\line{\hss#1\hss}}
,因此我们得到
\line{\hss ciao\\mondo\hss}
即成为
\hbox to \hsize{\hss ciao\\mondo\hss}
盒子启动后,展开后\\
我们得到(经过一些简化)
\hbox to\hsize{\hss ciao\egroup\centerline\bgroup mondo\hss}
因此,框已关闭,“ciao”将与右侧对齐。Next\centerline
被展开,并\bgroup
带有参数,因此我们有
\line{\hss\bgroup\hss}mondo\hss}
所以
\hbox to\hsize{\hss\bgroup\hss}mondo\hss}
右括号匹配,\bgroup
但mondo
由于\hss
其前面有两个括号,因此未居中。
请注意,\hbox<box specification>{<horizontal material}
允许水平材料被显式或隐式括号包围;宏参数周围的括号必须始终是显式的。
只是为了好玩,这里是另一个解决方案(它依赖于其\parfillskip
默认值,但可以很容易地推广)
\def\multicenter#1{%
\par
\begingroup
\leftskip=\parfillskip \parindent=0pt
\let\\=\par
#1\par
\endgroup
}
}
与上述解决方案的不同之处在于,这里过长的线条将会换行,而在\hss
上述基于的解决方案中,它们将会粘在边距中。
\halign
与基于的解决方案类似的基于的解决方案\hss
:
\def\multicenter#1{%
\par
\begingroup
\let\\=\cr
\tabskip=0pt plus 1fil
\halign to\hsize{\hidewidth\ignorespaces##\unskip\hidewidth\cr#1\crcr}
\endgroup
}
请注意,这两种新解决方案都允许在周围留有空格\\
。
答案2
\bgroup\egroup
您不能用以下代码包围未限定的(普通)宏参数:{}
我会用\halign
类似
\def\mcenterline#1{\par{%
\tabskip0pt plus 1fill
\let\\\cr\halign to \hsize{\hfill##\hfill\cr#1\crcr}}%
\par}
\noindent a\dotfill a
\mcenterline{aaa\\bb\\xxx x x x}
\bye
要查看原文的错误,请考虑:
\def\multicenter#1{\def\\{\egroup\centerline\bgroup}\centerline{#1}}
\tracingall
\multicenter{aaa\\bb\\xxx x x x}
\bye
产生
\multicenter #1->\def \\{\egroup \centerline \bgroup }\centerline {#1}
#1<-aaa\\bb\\xxx x x x
{\def}
{changing \\=macro:#1pt->#1}
{into \\=macro:->\egroup \centerline \bgroup }
\centerline #1->\line {\hss #1\hss }
#1<-aaa\\bb\\xxx x x x
\line ->\hbox to\hsize
{\hbox}
{entering adjusted hbox group (level 1) at line 4}
{restricted horizontal mode: \hss}
{the letter a}
\\->\egroup \centerline \bgroup
{end-group character }}
{leaving adjusted hbox group (level 1) entered at line 4}
%% goal height=643.20255, max depth=4.0
\centerline #1->\line {\hss #1\hss }
#1<-\bgroup
\line ->\hbox to\hsize
{vertical mode: \hbox}
{entering adjusted hbox group (level 1) at line 4}
{restricted horizontal mode: \hss}
{begin-group character {}
{entering simple group (level 2) at line 4}
{\hss}
{end-group character }}
{leaving simple group (level 2) entered at line 4}
{the letter b}
\\->\egroup \centerline \bgroup
{end-group character }}
{leaving adjusted hbox group (level 1) entered at line 4}
% t=10.0 g=643.20255 b=10000 p=0 c=100000#
\centerline #1->\line {\hss #1\hss }
#1<-\bgroup
\line ->\hbox to\hsize
{vertical mode: \hbox}
{entering adjusted hbox group (level 1) at line 4}
{restricted horizontal mode: \hss}
{begin-group character {}
{entering simple group (level 2) at line 4}
{\hss}
{end-group character }}
{leaving simple group (level 2) entered at line 4}
{the letter x}
{blank space }
{the letter x}
{blank space }
{the letter x}
{blank space }
{the letter x}
{\hss}
{end-group character }}
{leaving adjusted hbox group (level 1) entered at line 4}
% t=22.0 g=643.20255 b=10000 p=0 c=100000#
{vertical mode: blank space }
{\par}
特别要注意的#1
是\centerline
只是 \bgroup
并非中间的所有文本\bgroup
,\egroup
因此此后的扩展或多或少都是偶然的和不受欢迎的。