为什么 \\*(“此处换行,但没有分页符”)不起作用,以及如何修复这个问题?

为什么 \\*(“此处换行,但没有分页符”)不起作用,以及如何修复这个问题?

人们经常被教导“\\导致换行而不是段落中断”和“变体\\*还可以防止分页”。

(我在此确认egreg用户警告\\*不应使用”。)

\\*经常不起作用!什么时候不起作用\\*?如何修复?

以下代码生成一个脚注示例,然后生成一个正文示例。请注意,\\*在正文中使用可能更为常见。

\documentclass{article}
\usepackage{lipsum}


\begin{document}

\lipsum[1-4]\footnote{
  no asterisk \\ asterisk \\*
  no asterisk \\ asterisk \\*
  no asterisk \\ asterisk \\*
  no asterisk \\ asterisk \\*
  no asterisk \\ asterisk \\*
  % the pagebreak happens here
  last line}
\lipsum[5]


\lipsum[6-8]
\lipsum[2]

Line 1 \\*
  % the pagebreak happens here
Line 2 \\*
Line 3 \\*
Line 4 \\*
Line 5 \\
Line 6

\end{document}

答案1

理论

\\*如果在垂直模式下使用,则会引发错误;在水平模式下,它会执行以下操作:

\unskip        % remove any preceding spaces
\vadjust{\penalty 10000}% \nobreak in vertical mode after this line
\penalty 10000 % \nobreak in horizontal mode
\hfil          % fill current line
\penalty-10000 % force line break

因此看起来好像\nobreak两行之间有一个垂直模式,可以防止分页。

但是,如果 TeX 将段落的行放在垂直列表中会发生什么?

  • 它在框之间插入行间粘连(取决于\baselineskip\lineskiplimit和的值\lineskip)。不可丢弃项目后的粘连将构成断点。

  • 因此 TeX 在行间粘连之前添加了一个惩罚来控制分页。这个惩罚加上\interlinepenalty一些根据上下文而定的其他惩罚(\clubpenalty\widowpenalty\displaywidowpenalty\brokenpenalty)。那么分页点就是这个惩罚,而不是行间粘连。

通过添加惩罚项,\vadjust可以将其放在当前行之后,在行间惩罚项和行间粘连之前。因此,我们有:

\hbox                         % the line
\penalty10000                 % \nobreak via \vadjust
\penalty\interlinepenalty+... % interline penalty
\vskip                        % interline glue
\hbox                         % next line

因此,如果行间惩罚小于 10000,尽管使用了 ,我们也会有一个断点。如果行间惩罚为 10000 或更大,那么无论是否使用\\*,我们都不会有一个断点。\nobreak\\*

然而,有一种情况\\*确实会阻止换行。也就是说,“TeXbook”并不总是说实话:有一种情况是,TeX 确实不是添加行间粘连。它试图变得聪明,并将行间惩罚合理化为零。它可能会认为:行间粘连之后\hbox——我们有一个断点;惩罚为零——既不好也不坏,因为已经有一个断点,我们不需要它。在附录 A 中可以找到练习 14.26 的答案:

(当总惩罚为零时,就像本例中的第 3 行和第 4 行之间一样,实际上没有插入任何惩罚。)

然后\nobreak开始\\*

\hbox          % line box
\penalty 10000 % of \\* via \vadjust
\vskip <interline glue>
\hbox          % next line

瞧,令人惊讶的是,分页符被阻止了。当然,这种过度优化并不是一个“错误”(事实上,TeX 按照定义是没有错误的),我们称之为“设计缺陷”。;-)

为了说明,下面是一个用于实验/研究的 ini-TeX(或纯 TeX)示例。宏\NPB模拟\\*

% iniTeX or plain TeX
\showboxbreadth=10000
\showboxdepth=10000
\tracingonline=1
\catcode`\{=1
\catcode`\}=2
\font\rm=cmr10
\rm
\baselineskip=12pt
\parfillskip=0pt plus 1fil\relax
\hsize=2in
\vsize=4in

\interlinepenalty=1
\clubpenalty=-1
\widowpenalty=150

\def\NPB{% \\*
  \unskip
  \vadjust{\penalty10000}%
  \penalty10000\hfil\penalty-10000 %
}

\noindent
A\NPB B\NPB C

\scrollmode
\showlists
\end

控制台输出:

### vertical mode entered at line 0
### current page:
\glue(\topskip) 0.0
\hbox(6.83331+0.0)x144.54, glue set 137.03998fil
.\rm A
.\penalty 10000
.\glue 0.0 plus 1.0fil
.\penalty -10000
.\glue(\rightskip) 0.0
\penalty 10000
\glue(\baselineskip) 5.16669
\hbox(6.83331+0.0)x144.54, glue set 137.45663fil
.\rm B
.\penalty 10000
.\glue 0.0 plus 1.0fil
.\penalty -10000
.\glue(\rightskip) 0.0
\penalty 10000
\penalty 151
\glue(\baselineskip) 5.16669
\hbox(6.83331+0.0)x144.54, glue set 137.31776fil
.\rm C
.\penalty 10000
.\glue(\parfillskip) 0.0 plus 1.0fil
.\glue(\rightskip) 0.0
total height 30.83331
 goal height 289.07999
prevdepth 0.0, prevgraf 3 lines

! OK.
l.28 \showlists

第一行之间的内容\hbox

\penalty 10000
\glue(\baselineskip) 5.16669

第一个惩罚来自\vadjust{\penalty10000}。行间惩罚总计为零:\interlinepenalty+ \clubpenalty= 1 - 1 = 0

第二种情况:

\penalty 10000
\penalty 151
\glue(\baselineskip) 5.16669

行间惩罚不被抑制:\interlinepenalty+ \widowpenalty= 1 + 150 = 151。此惩罚允许在此处分页。

实践

以下部分继承自此回答更具体问题变体。

问题在于自动插入的。它通常小于 10000,并且即使其前面有(= )\interlinepenalty也允许分页。\nobreak\penalty10000

下面使用了一种解决方法。不是结束行,而是结束段落。然后需要逆转和避免\parskip和的影响:\parindent

\documentclass{article}
\usepackage{lipsum}

\newcommand*{\NLS}{%
  \par
  \nobreak
  \vspace{-\parskip}%
  \noindent
  \ignorespaces
}

\begin{document}

\lipsum[1-4]\footnote{
  no asterisk \\ asterisk \NLS
  no asterisk \\ asterisk \NLS
  no asterisk \\ asterisk \NLS
  no asterisk \\ asterisk \NLS
  no asterisk \\ asterisk \NLS
  last line}
\lipsum[5]  

\end{document}

第1页 第2页

然而,这仍然是一种变通方法,并没有为 提供正确的实现\\*。通过将一个段落拆分为两个段落,插入 之前和之后的换行符最多\par增加两个行间惩罚,\widowpenalty或。也就是说,如果增加或现在将行间惩罚增加到 10000,\clubpenalty则可以作为副作用禁止额外的分页符。\widowpenalty\clubpenalty

另一种情况问题较少:如果插入 的换行符\par会变成\clubpenalty\widowpenalty,那么这个惩罚现在就消失了。但由于我们已经禁止了 的分页符\nobreak,因此额外的惩罚损失并不重要。

相关内容