我正在阅读 source2e.pdf 但在理解 LaTeX 2ε 的定义的含义方面遇到了问题\@esphack
:
类似 的命令\label{...}
本身不会/不应产生任何可见的输出,在源/.tex 输入文件中可能会被空格包围。如果是这样,您不需要两个空格标记,因为这会使水平粘连加倍。
如果我理解正确的话,\@bsphack
那么\@esphack
在标记和处理命令之后,它们可以避免出现空间标记,以防在标记和处理命令之前已经出现了一个空间标记。
让我们看看的定义\@bsphack
:
> \@bsphack=macro:
->\relax \ifhmode \@savsk \lastskip \@savsf \spacefactor \fi .
l.1 \show\@bsphack
换句话说:
当处于水平模式或受限水平模式时,将 的值保存为\lastskip
,\@savsk
并将 的值保存\spacefactor
为\@savsf
。
现在让我们看一下的定义\@esphack
:
> \@esphack=macro:
->\relax \ifhmode \spacefactor \@savsf \ifdim \@savsk >\z@ \ifdim \lastskip =\z
@ \nobreak \hskip \z@skip \fi \ignorespaces \fi \fi .
l.2 \show\@esphack
换句话说:
当处于水平模式或受限水平模式时,则:
- 将 的值恢复
\spacefactor
为 保存的值\savsf
。 - 如果
\@savsk
大于零,即,如果在执行开始时调用的命令之前存在一些水平粘连\@bsphack
,则执行
\ifdim \lastskip =\z@ \nobreak \hskip \z@skip \fi \ignorespaces
。
我理解这\ignorespaces
很有意义,因为在执行开始时调用的命令之前已经存在一些水平粘连\@bsphack
。
但我不明白
\ifdim \lastskip =\z@ \nobreak \hskip \z@skip \fi
-part 有什么用处。
这有什么意义呢?
在执行这种情况时, 中保存的值\@savsk
大于\z@
,因此可以得出结论,在启动时调用的命令中的某些内容确实将\@bsphack
的值更改为。\lastskip
\z@
但执行类似的操作\nobreak\hskip\z@skip
不会撤销该更改/不会恢复\lastskip
到其先前的值。
\hskip
因此:执行零宽度的要点/意义/好处是什么?
如果您希望\lastskip
恢复,那么不应该是这样的:
\def\@esphack{%
\relax
\ifhmode
\spacefactor\@savsf
\ifdim\@savsk>\z@
\ifdim\lastskip=\z@
\nobreak
\hskip-\@savsk
\nobreak
\hskip\@savsk
% the total skip is zero and \lastskip is restored.
\fi
\ignorespaces
\fi
\fi
}%
或者也许只是
\def\@esphack{%
\relax
\ifhmode
\spacefactor\@savsf %now \spacefactor is restored.
\nobreak
\hskip-\@savsk
\nobreak
\hskip\@savsk
% the total skip is zero and \lastskip is restored.
\ifdim\@savsk>\z@
\ignorespaces
\fi
\fi
}%
是否有可能在之前的某个版本中,是这样完成的,而在后来的版本中,有人错误地将其“优化”
\nobreak\hskip-\@savsk\nobreak\hskip\@savsk
为\nobreak\hskip\z@skip
,而忽略了不再恢复这一功能\lastskip
?
如果我理解正确的话,您需要\lastskip
正确恢复,否则具有连续序列的东西\@bsphack..\@esphack
(例如)\label{foo}\label{bar}
将无法正常工作:
如果现在你做了类似
A \label{foo} \label{bar} A
或的事情
A \label{foo}\label{bar} A
,\lastskip
在任何情况下都会为 0,之后\label{foo}
会影响的行为,\label{bar}
因为\label{bar}
\@savsk
不会大于\z@
任何,所以\ignorespaces
虽然应该执行,但不会执行!
通过下面的例子,你可以看到重新定义时出现的细微差别,\@esphack
从而可以恢复\lastskip
:
\documentclass{article}
\newsavebox\mybox
\begin{document}
\par\noindent\begin{lrbox}{\mybox}
\verb*|A\label{1}B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A\label{1}B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{2} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{2} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{3}\label{4} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{3}\label{4} B
\par\noindent\begin{lrbox}{\mybox}
\verb*| \label{5} \label{6} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{5} \label{6} B
\makeatletter
\def\@esphack{%
\relax
\ifhmode
\spacefactor\@savsf
\ifdim\@savsk>\z@
\ifdim\lastskip=\z@
\nobreak
\hskip-\@savsk
\nobreak
\hskip\@savsk
% the total skip is zero and \lastskip is restored.
\fi
\ignorespaces
\fi
\fi
}%
\makeatother
\noindent\null\hrulefill\null
\par\noindent\begin{lrbox}{\mybox}
\verb*|A\label{a}B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A\label{a}B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{b} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{b} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{c}\label{d} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{c}\label{d} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{e} \label{f} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{e} \label{f} B
\end{document}
我的修改\@esphack
有缺点吗?
我是否忽略了一些警告/相关内容?
答案1
您可以在源代码中看到更多更改注释和旧版本:
% \begin{macro}{\@esphack}
% Companion to |\@bsphack|. If this command is not properly paired
% with |\@bsphack| one might end up with a low-level \TeX{} error:
% ``BAD spacefactor''. One possible cause is calling |\@bsphack| in
% vertical mode, then doing something that gets you (sometimes) into
% horizontal mode and finally calling |\@esphack|. Even if no error
% is generated that is wrong, because |\@esphack| will then use the
% saved values for |\@savsk| and |\@savsf| from some earlier
% invocation of |\@bsphack| which will have nothing to do with the
% current situation.
% \changes{v1.3d}{2015/01/11}{Allow hyphenation (Donald Arseneau pr/3498) (latexrelease)}
% \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2018/10/10}%
%<latexrelease> {\@esphack}{hyphenation and nobreak after space hack}%
%<*2ekernel|latexrelease>
\def\@esphack{%
\relax
\ifhmode
\spacefactor\@savsf
\ifdim\@savsk>\z@
% \end{macrocode}
% \changes{v1.3f}{2015/11/07}
% {Only space if there is no space at the end of the hlist latex/4443}
% \begin{macrocode}
\ifdim\lastskip=\z@
\nobreak \hskip\z@skip
\fi
\ignorespaces
\fi
% \end{macrocode}
% \changes{v1.3i}{2018/10/10}
% {Don't introduce breakpoints if @nobreak is true and after sections}
% \begin{macrocode}
\else
\ifvmode
\if@nobreak\nobreak\else\if@noskipsec\nobreak\fi\fi
\fi
% \end{macrocode}
%
% \begin{macrocode}
\fi}%
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2015/10/01}%
%<latexrelease> {\@esphack}{hyphenation and nobreak after space hack}%
%<latexrelease>\def\@esphack{%
%<latexrelease> \relax
%<latexrelease> \ifhmode
%<latexrelease> \spacefactor\@savsf
%<latexrelease> \ifdim\@savsk>\z@
%<latexrelease> \ifdim\lastskip=\z@
%<latexrelease> \nobreak \hskip\z@skip
%<latexrelease> \fi
%<latexrelease> \ignorespaces
%<latexrelease> \fi
%<latexrelease> \fi}%
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2015/01/01}%
%<latexrelease> {\@esphack}{hyphenation and nobreak after space hack}%
%<latexrelease>\def\@esphack{%
%<latexrelease> \relax
%<latexrelease> \ifhmode
%<latexrelease> \spacefactor\@savsf
%<latexrelease> \ifdim\@savsk>\z@
%<latexrelease> \nobreak \hskip\z@skip
%<latexrelease> \ignorespaces
%<latexrelease> \fi
%<latexrelease> \fi}%
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease> {\@esphack}{hyphenation and nobreak after space hack}%
%<latexrelease>\def\@esphack{%
%<latexrelease> \relax
%<latexrelease> \ifhmode
%<latexrelease> \spacefactor\@savsf
%<latexrelease> \ifdim\@savsk>\z@
%<latexrelease> \ignorespaces
%<latexrelease> \fi
%<latexrelease> \fi}%
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
% \end{macrocode}
% \end{macro}
基本上,您查询的位,您需要添加一个空格(或零宽度)以免抑制连字符,然后需要添加\nobreak
以便空格不会引入断点。
由于您知道如何使用\hskip-\zzz\hskip\zzz
以下测试,因此将 0pt 跳过拆分为此处效果更好,但是,这会使水平列表稍微容易受到任何以下删除跳过(而不仅仅是测试它)的影响,因为它只会删除一半的对,从而在列表中留下可能意外的负跳过。\lastskip
\unskip
我想出了这个表格示例,尽管可以说在这种情况下结果也更好,因为剩下的负跳过抵消了第一个索引之前的原始空间。但其他合理用途\unskip
需要检查......
\documentclass{article}
\newsavebox\mybox
\makeindex
\tabcolsep=0pt
\begin{document}
\par\noindent\begin{lrbox}{\mybox}
\verb*|A\label{1}B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A\label{1}B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{2} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{2} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{3}\label{4} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{3}\label{4} B
\par\noindent\begin{lrbox}{\mybox}
\verb*| \label{5} \label{6} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{5} \label{6} B
\begin{tabular}{|r|}
A A \index{A}\\
B B \index{B}\\
\end{tabular}
\makeatletter
\def\@esphack{%
\relax
\ifhmode
\spacefactor\@savsf
\ifdim\@savsk>\z@
\ifdim\lastskip=\z@
\nobreak
\hskip-\@savsk
\nobreak
\hskip\@savsk
% the total skip is zero and \lastskip is restored.
\fi
\ignorespaces
\fi
\fi
}%
\makeatother
\noindent\null\hrulefill\null
\par\noindent\begin{lrbox}{\mybox}
\verb*|A\label{a}B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A\label{a}B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{b} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{b} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{c}\label{d} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{c}\label{d} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{e} \label{f} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{e} \label{f} B
\begin{tabular}{|r|}
A A \index{A}\\
B B \index{B}\\
\end{tabular}
\end{document}
我认为我们可以使用 e-tex测试来避免添加虚假的 -ve/+ve 胶水对或虚假的 1sp 胶水节点,而不是将其用作\ifdim\lastskip>0pt
“是否存在前置胶水”的测试:\ifnum\lastnodetype=11
\documentclass{article}
\newsavebox\mybox
\makeindex
\tabcolsep=0pt
\begin{document}
\par\noindent\begin{lrbox}{\mybox}
\verb*|A\label{1}B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A\label{1}B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{2} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{2} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{3}\label{4} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{3}\label{4} B
\par\noindent\begin{lrbox}{\mybox}
\verb*| \label{5} \label{6} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{5} \label{6} B
\begin{tabular}{|r|}
A A \index{A}\\
B B \index{B}\\
\end{tabular}
\makeatletter
\def\@bsphack{%
\relax
\ifhmode
\@savsk\lastskip
\ifdim\@savsk=\z@\ifnum\lastnodetype=11 \@savsk1sp \fi\fi
\@savsf\spacefactor
\fi}
% \def\@esphack{%
% \relax
% \ifhmode
% \spacefactor\@savsf
% \ifdim\@savsk>\z@
% \ifdim\lastskip=\z@
% \nobreak
% \hskip1sp
% % the total skip is zero and \lastskip is restored.
% \fi
% \ignorespaces
% \fi
% \fi
% }%
\makeatother
\noindent\null\hrulefill\null
\par\noindent\begin{lrbox}{\mybox}
\verb*|A\label{a}B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A\label{a}B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{b} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{b} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{c}\label{d} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{c}\label{d} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{e} \label{f} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{e} \label{f} B
\begin{tabular}{|r|}
A A \index{A}\\
B B \index{B}\\
\end{tabular}
\end{document}