当 vbox 开始一行并位于文本之前时,如何防止 vbox 和文本之间强制换行?

当 vbox 开始一行并位于文本之前时,如何防止 vbox 和文本之间强制换行?

我很惊讶地从 复制了一个字符(我花了很多时间来修剪周围的空格),结果\vbox却发现只要它在文本前面(在同一行),它就会强制换行。下面是一个简化版本,它会产生相同的结果。我需要@出现在 的同一行上hello world,而不需要将两者都放在 中\hbox(这是我发现的唯一可行的方法,但由于设计问题,我无法在原始代码中仅使用hello world--only @-- 来包含它们)。

PS 让我们将解决方案限制为在 XeLaTeX 中编译的纯 TeX 代码。

\documentclass[border=5mm,varwidth]{standalone}

\usepackage{color}
\pagecolor{black}
\color{white}

\begin{document}
  \newbox\zT
  \setbox\zT\vbox{\makeatletter@\makeatother}
  \copy\zT hello world\par % try 1 (failed)
  \hbox{\copy\zT}hello world % try 2 (failed)
\end{document}

预期产出(近似值):

答案1

PS 让我们将解决方案限制为在 XeLaTeX 中编译的纯 TeX 代码。

您的示例中没有使用在纯 TeX 中定义的命令,纯 TeX 有一个\newbox命令,但定义完全不同,并且其他命令都不是纯 TeX 中定义的命令,它们要么是 LaTeX 命令,要么是 TeX 原语。

你还没有说你想做什么,但是 LaTeX 框命令旨在避免这样的问题(并且\setbox在加载颜色后使用 tex 原语特别危险,你很容易生成无效的 PDF 输出而没有任何警告)

LaTeX 标记为

\documentclass[border=5mm,varwidth]{standalone}

\usepackage{color}
\pagecolor{black}
\color{white}

\begin{document}
  \newsavebox\zT
  \sbox\zT{@}

  \usebox{\zT} hello world
\end{document}

在此处输入图片描述

要查看原始注释中的问题,请注意,方框不会启动段落,因此在以下任一情况下,

\vbox{...}
Hello World

或者

\hbox{...}
Hello World

段落从H开始,框内容位于段落之前(即上方)。

通常的解决方案是\leavevmode在框前使用来开始段落所以\leavevmode\hbox{@}或更好\mbox{@}或使用框寄存器,\leavevmode\copy\zT或更好\usebox{\zT}

但在你的情况下,盒子无论如何都放不下左边,H因为你有

\vbox{@}

因此,这是在 vmode 内开始一个段落,因此段落文本(\indent@\parfillskip)将被换行到宽度为的行\hsize,因此 vbox 内容包括\hbox宽度为的\hsize(即\textwidth)而不仅仅是@

TeX 可以向您显示由以下方式构造的框\vbox{@}

\documentclass[border=5mm,varwidth]{standalone}

\usepackage{color}
\pagecolor{black}
\color{white}

\begin{document}

\showoutput
\setbox\zT\vbox{@}
\showbox\zT
\end{document}

生产

\vbox(6.94444+0.0)x345.0
.\hbox(6.94444+0.0)x345.0, glue set 337.2222fil
..\hbox(0.0+0.0)x0.0
..\OT1/cmr/m/n/10 @
..\penalty 10000
..\glue(\parfillskip) 0.0 plus 1.0fil
..\glue(\rightskip) 0.0

因此 vbox 包含一个宽度为零的 hbox,\hsize其中包含一个大小为零的空 hbox(用于段落缩进)、@ 字符和\parfillskip粘合\rightskip节点。

答案2

如果您想使用纯 TeX,请不要在 LaTeX 中嵌入内容。

从你的帖子中我猜测您想要修剪某个字符周围的空白。例如,以 为例\times

这是周围没有空白的字符,周围的细线框只是为了显示边界框。

在此处输入图片描述

如果要使用剪切的字符,可以将其设置到一个框中,然后\copy将该框设置好,但是记住命令\copy不会从垂直模式变为水平模式。

\newbox\btimesbox
% remove the white space on the left and on the right
\setbox\btimesbox=\hbox{\kern-0.35ex$\times$\kern-0.35ex}
% remove the white space at the bottom
\setbox\btimesbox=\hbox{\raise-0.03ex\box\btimesbox}
% we want the depth to be zero
\dp\btimesbox=0pt
% remove the white space at the top
\ht\btimesbox=1.1ex

\def\btimes{\leavevmode\copy\btimesbox}

\btimes\ hello world

t\btimes t

t$\times$t

\bye

在此处输入图片描述

答案3

它不起作用,因为 a\vbox总是自动具有宽度\hsize,即整个文本块的宽度。您可以执行类似操作\vbox{\hsize=1em...},但这只是无稽之谈,因为有更好的解决方案。

我向你提出三项建议。

  1. 在 里面定义一个宏\makeatletter...other,这样会冻结 宏里面的 catcode @,所以用宏排版@不会受到周围 catcode 的影响。

    \makeatletter
    \newcommand*\letterat{@}
    \makeatother
    
  2. 定义一个字符常量。这将在您提供的代码处插入字符。Catcodes 不适用于字符常量。缺点是这会占用一个寄存器,但如今有了 e-TeX,这实际上不是问题。

    \chardef\letterat=`\@
    
  3. 将字符放入水平盒子中。这有几个缺点。首先,字符根本不适应周围的字体,其次,它还需要一个寄存器,第三,它不能放在前导码中,因为必须在分配盒子时加载字体。

    \newbox\atbox
    \setbox\atbox=\hbox{@}
    \newcommand*\letterat{\leavevmode\unhcopy\atbox}
    

相关内容