宏定义中的问题(纯 TeX)

宏定义中的问题(纯 TeX)

我正在尝试编写一个\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}

右括号匹配,\bgroupmondo由于\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因此此后的扩展或多或少都是偶然的和不受欢迎的。

相关内容