我目前正在仔细研究 TeX 如何操纵跳过,但无法找到具有负拉伸或收缩成分的跳过的实际用例,例如下面的\Askip
和。\Bskip
\newskip\Askip
\newskip\Bskip
\Askip 0pt plus -2pt minus 3pt
\Bskip 0pt plus 1fil minus -4bp
它们会导致奇怪的情况。例如,将具有较大负拉伸分量的垃圾箱放入一个略微未充满的盒子中,会导致其他垃圾箱按其拉伸分量的比例收缩。
\hbox to 200pt{A B C\hskip 0pt plus -50pt}\bye
实际情况是,由于盒子未充满,TeX 会查看可用拉伸分量的总和。由于总和为负数,因此拉伸分量会乘以负数。
所以,显然这个例子是没用的,但是有没有一些更有用的例子来说明负胶有什么用途呢?
答案1
简而言之,负向拉伸和收缩可以与正向拉伸和收缩相结合以“抵消”,正如@egreg 和@David 所提到的。这使得换行算法可以自动做出一些复杂的选择。
这才是完整的答案,但只是为了详细说明:TeXbook但这些内容在论文中得到了更好的解释和组织将段落分成几行作者:Knuth 和 Plass(你可以在网上找到它;也转载于数字排版并进行了一些小修改)。
论文中给出的第一个例子是:
尽管盒子/粘合/惩罚模型乍一看似乎只针对对齐文本的问题,但我们现在将看到,它足够强大,可以适应类似的不对齐排版问题:[...] 这个想法是让单词之间的空格由序列表示
胶水(0,18,0)
惩罚(0,0,0)
胶水(6,-18,0)而不是我们用于对齐排版的“glue(6,3,2)”。[...] 如果在惩罚处发生中断,则行上的可拉伸性将为 18 个单位,并且将在中断后丢弃“glue(6,-18,0)”,以便下一行从左对齐开始。另一方面,如果没有发生中断,则净效果是产生 glue(6,0,0),表示没有拉伸或收缩的正常空间。
请注意,第二个粘连项中的可拉伸性 -18 没有物理意义,但它很好地抵消了第一个粘连项中的可拉伸性 +18。负可拉伸性有几个有趣的应用,因此读者在继续下面更复杂的构造之前应该仔细研究这个例子。
为了用 TeX 语法重现上述内容(某种程度上),请使用以下命令编译以下内容pdftex
:
\def\randomword{\ifcase\pdfuniformdeviate6 one\or two\or three\or four\or five\or six\fi}
\def\oneword{\randomword\hskip 0pt plus 18pt\penalty 0\hskip 3.333pt plus -18pt\relax}
\def\tenwords{\oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword}
\def\paragraph{\tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords}
\hsize=4.5in
\paragraph
\bye
得到如下结果:
(这不是\raggedright
在 TeX 中实现的方式——使用\rightskip
——但是这在每一行上添加了可伸缩性,而不是单词之间的恒定间距。)
正如论文进一步指出的,同样的想法也适用于在右侧不齐的段落中插入可选连字符,以及在“居中不齐”的段落中插入可选连字符:
\def\randomword{\ifcase\pdfuniformdeviate6 one\or two\or three\or four\or five\else six\fi}
\def\oneword{%
\randomword
\hskip 0pt plus 18pt
\penalty 0
\hskip 3.333pt plus -36pt\relax
\hbox{}
\penalty 10000
\hskip 0pt plus 18pt
}
\def\tenwords{\oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword \oneword}
\def\paragraph{%
\noindent
\hskip 0pt plus 18pt
\tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \tenwords \randomword
\hskip 0pt plus 18pt
\penalty -10000
}
\hsize=4.5in
\paragraph
\bye
— 这个想法是,如果在 处断开\penalty 0
,那么断开的线将以 的胶水结束\hskip 0pt plus 18pt
,而下一条线将以 的胶水开始\hbox{}\penalty 10000\hskip 0pt plus 18pt
(所以基本上就是那个拉伸量),而如果没有断开,那么所有的胶水都会抵消。
然后,这个想法用于排版不同宽度的计算机程序,只需进行简单的改变\hsize
即可:
(Knuth 编写了一个预处理器来为这些 PASCAL 程序生成 TeX 文件;它被称为 BLAISE。)
最后,
我们将要研究的最后一个断行应用是作者迄今为止遇到的最困难的一个;由于盒子/粘合/惩罚原语的全部威力并没有立即显现出来,因此只有在获得了两年多更直接的断行任务经验之后才解决了这个问题。
这是对某个索引进行排版,并通过改变来获得以下任一项\hsize
:
每个条目的特点如下:
有一个名称(可能太长,一行无法容纳),后面跟着点引导,后面跟着一串评论编号(可能太长,一行无法容纳)。
第一行之后的所有行都应缩进(悬挂缩进)。
如果姓名部分断开,则应左对齐(右边不齐);如果数字部分断开,则应右对齐(左边不齐)并缩进。
如果点引导结束一行,它们应该在行末之前的一定距离处停止;同样,右边参差不齐的线条应该在行末之前的一定(其他)距离处具有最大宽度。
尽量减少空白,并且(其次)尽量减少数字的行数。
有一种方法可以实现所有这些,同时保持输入简单如下:
ACM Symposium on Theory of Computing, Eighth Annual (Hershey, %
Pa., 1976)\:1879, 4813, 5414, 6918, 6936, 6937, 6946, 6951, %
6970, 7619, 9605, 10148, 11676, 11687, 11692, 11710, 13869
解决方案涉及负拉伸和收缩:请参阅论文,或参阅“7. 段落操作”附录 D:肮脏的伎俩TeXbook,第 392-394 页。本文接着给出了一个“代数”,可以帮助人们想出完成此类任务的正确技巧。
相同的想法也适用于分页;请参阅\beginsection
、plain.tex
或\vfilneg
或包中needspace
。
答案2
正如@egreg 在评论中提到的,它们通常与相等的正值配对。
普通和乳胶都有
\def\filbreak{\par\vfil\penalty-200\vfilneg}
如果发生中断,则负拉伸将被丢弃在下一页的顶部,但如果没有发生中断,它会抵消fil
惩罚之前的空间,使总拉伸为零。
答案3
可能不完全符合要求,但绝对负跳过在创建复合符号时很有用,例如
x \rightarrow\mskip-15mu\rightarrow\mskip-15mu\rightarrow y
会给你
值得注意的是\llap
,、\rlap
和\clap
它们的垂直朋友都是基于\hss
或,\vss
它们是用无限(正)收缩和拉伸定义的原语。 \llap
对于将页码定位在目录中右侧非常有用。如果没有这些功能,就不会存在边注。