\dotfill 跨越换行符

\dotfill 跨越换行符

我想编写一个简单的词汇表,使用类似下面的代码。

\documentclass{article}

\usepackage{multicol}

\newcommand{\itemlex}[2]{%
    \mbox{#1} \dotfill{} \mbox{\itshape #2}%
\par}

\setlength{\parindent}{0pt}
\setlength{\parskip}{3pt plus 2pt}

\begin{document}

\begin{multicols}{2}
    \itemlex{un mot court}{a short word}
    \itemlex{un mot beaucoup plus long}{a much longer word}
    \itemlex{lorem}{lorem}
    \itemlex{ipsum}{ipsum}
    \itemlex{dolor}{dolor}
    \itemlex{sit}{sit}
    \itemlex{amet}{amet}
\end{multicols}

\end{document}

结果如下:

结果

有没有办法\dotfill在“必要时”强制跨越换行符,即如下所示?

在此处输入图片描述

(这是用\\和 第二个手动生成的\dotfill,我希望在需要时可以自动化生成。)

答案1

我的代码的想法是从两个\dotfils 创建点。第一个(只有一个 el)由 定义\hfil,第二个是标准的 Plain-TeX\dotfill定义,由 定义\hfill。当您\itemlex只打印单行时,第一行将\dotfil获得零空间,第二行将\dotfill被拉伸。当您\itemlex需要两行时,行将在 处断开\penalty0,因此第一行由第一行填充\dotfil,第二行使用第二行\dotfill。因为第二行由(两个 el)\dotfill创建,所以寄存器的标准设置(即)在段落末尾创建零空间。\hfill\parfillskip1fil

请注意,第二个\dotfill是受“保护”的,\null因为是\dotfill可丢弃的项目(如果在它之前立即换行,它将被删除)。它受“保护”是\nobreak因为我们不想在\dotfill它本身处换行。

\def\itemlex#1#2{%
   \noindent \hbox{#1} \dotfil\penalty0 \null\nobreak\dotfill ~\hbox{#2}\par
}
\def\dotfil{\cleaders\hbox{$\mkern1.5mu.\mkern1.5mu$}\hfil}

\hsize=7cm

   \itemlex{un mot court}{a short word}
   \itemlex{un mot beaucoup plus long}{a much longer word}
   \itemlex{lorem}{lorem}

\bye

答案2

“领导者”的理念是排列尽可能多的“领导者框”,以适应间隙。适合间隙的领导者框的总尺寸可以略小于间隙本身。

\leaders将引导框紧密地排列在一起,从周围框的边缘开始,但只显示完全在间隙所占空间内的引导框。这样,例如,可以让同一垂直框内不同行中相同类型的水平引导元素垂直对齐。

\cleaders将尽可能多的引导框紧密地排列在一起以适应间隙,并将该结构置于间隙的中心。

\xleaders将尽可能多的前导盒装入间隙中,并在第一个前导盒之前、所有这些前导盒之间以及最后一个前导盒之后插入相同大小的胶水,以使胶水和前导盒的构造具有与间隙相同的尺寸。

如果使用\leaders,使得不同行(如果是垂直引导线,则为列)的引导框彼此齐平,对于至少一个带有引导框的框,间隙需要至少是引导框的两倍大。

Wipet 的想法是创建一个带有“ ”前导框的水平粘合块,\hfil以及另一个带有“ \hfill”的水平粘合块,并在两者之间插入一个惩罚来“告诉” TeX 这里允许换行/断开,这就是解决问题的要点/本质。

如果没有换行,粘连\hfill比粘连“膨胀”得多\hfil,会占据剩余的行宽,而\hfil粘连则根本没有空间,因为粘连的“膨胀”性要大得多\hfill,所以根本不会创建粘连。当出现换行时,一个粘连会从右侧填充顶行的剩余部分,另一个粘连会从左侧填充底行。

对于 Wipet 的方法,我没什么可补充的。不过,我试图满足您在评论中对 Wipet 的回应提出的迟来的要求,即点应左右对齐,不同行中的点应垂直对齐:

您尝试使用\dotfill。但是\dotfill不适用于您希望不同行的水平引线元素垂直对齐的情况,首先是因为\dotfill使用\cleaders,其次是因为要设置为引线的框是一个宽度为 .44em 的框,其中水平居中设置了一个点。因为 的引线框宽度是固定的\dotfill,所以点之间的间隙宽度也是固定的。

从上面关于不同类型领导者的讨论来看:

  • 由于不同线上的点应垂直齐平,因此只会\leaders成为问题。\cleaders并且\xleaders是不可能的。
  • 由于点要与周围垂直框的左侧和右侧边缘对齐,
    • 引导框不应包含单个居中点,而应包含左侧的一个点、一个间隙和右侧的另一个点,该点的宽度不计入引导框的宽度。左侧的点确保行首的点引导与周围框的左边缘对齐。右侧的点与下一个引导框左侧的点重叠,最后一个引导框除外。这样,如果引导框的宽度按如下所述计算,则一行文本末尾的点引导将与周围框的右边缘对齐。

    • 需要根据以下信息设置/计算引导框的宽度:

      • 线宽(\hsize),
      • 所需的引导框的最小宽度,
      • 点的宽度

      如下:

      ⟨leader-box的宽度⟩ = ( ⟨linewidth⟩ − ⟨dot的宽度⟩ ) / ( ( ⟨linewidth⟩ − ⟨dot的宽度⟩ ) div ⟨leader-box所需的最小宽度⟩ )

      我还没有仔细考虑如何在 TeX 中准确进行此类计算。
      但有一个长度需要计算。TeX 中最小的长度单位是缩放点 (sp)。

      对于接受表示 ⟨number⟩ 数量的计数寄存器的算术运算,您也可以使用维度寄存器或跳过寄存器,只要您不使用,\the而是让 TeX 直接获取相关维度寄存器或跳过寄存器的值即可。如果您这样做,那么当它被标准化为缩放点时,TeX 会假设属于相关长度量的数值。

      因此,在进行计算时,您可以使用维度寄存器/维度参数(例如计数寄存器)将长度视为标准化为缩放点,避免应用\the它们。

      如果你感兴趣的话,这里有一个 TeX 可以理解的长度单位转换表:

      pt 点(本手册中的基线相隔 12 pt)
      pc 派卡(1 pc = 12 pt)
      in 英寸(1 in = 72.27 pt)
      bp 大点(72 bp = 1 in)
      cm 厘米(2.54 cm = 1 in)
      mm 毫米(10 mm = 1 cm)
      dd 迪多点(1157 dd = 1238 pt)
      cc 西塞罗(1 cc = 12 dd)
      sp 缩放点(65536 sp = 1 pt)

      下面的方法\numexpr也许能够计算出所需引导框的宽度:

      \settowidth\dotwidth{.}%
      \setlength\minimumleaderboxwidth{.44em}%
      \setlength\leaderboxwidth{%
        \dimexpr
          \numexpr(\hsize-\dotwidth)/(%
            ((\hsize-\dotwidth)/\minimumleaderboxwidth)%
            \ifnum
              \numexpr((\hsize-\dotwidth)/\minimumleaderboxwidth)*(\hsize-\dotwidth)\relax>\numexpr\hsize-\dotwidth\relax
              -1%
            \fi
          )\relax
        sp\relax
      }%
      

在下面的例子中,创建了一个带有网格的垂直框,该网格显示了所创建的点的水平位置\leaders

在其上放置另一个框,其中创建带有各种引线的文本。

\documentclass{article}

\usepackage{multicol}

\usepackage{xcolor}

\newbox\textbox
\newbox\gridbox

\newlength\leaderboxwidth
\newlength\dotwidth
\newlength\minimumleaderboxwidth
\newcommand\calculateleaderparameters{%
  \settowidth\dotwidth{.}%
  \setlength\minimumleaderboxwidth{.44em}%
  \setlength\leaderboxwidth{%
    \dimexpr
      \numexpr(\hsize-\dotwidth)/(%
        ((\hsize-\dotwidth)/\minimumleaderboxwidth)%
        \ifnum
          \numexpr((\hsize-\dotwidth)/\minimumleaderboxwidth)*(\hsize-\dotwidth)\relax>\numexpr\hsize-\dotwidth\relax
          -1%
        \fi
      )\relax
    sp\relax
  }%
}%

\newcommand*\Dotfillleaders{\leaders\hbox to\leaderboxwidth{.\hss\rlap{.}}}
\newcommand*\mybreak{%
  \unskip
  \nobreak
  \Dotfillleaders\hskip2\leaderboxwidth\nobreak
  \Dotfillleaders\hfil
  \penalty 0 \hfilneg
  \null\nobreak
  \Dotfillleaders\hskip\the\dimexpr2\leaderboxwidth\relax plus 1fil\nobreak
  \null\nobreak\kern\dotwidth\nobreak
}


\csname @ifdefinable\endcsname\itemlex{%
  \def\itemlex#1#2\par{%
    {%
      % The command \calculateleaderparameters can be
      % moved into the multicols-environment instead of 
      % calculating the same things again and again with each instance 
      % of \itemlex. If you do that, \calculateleaderparameters
      % needs to be called within the multicols-environment right
      % after beginning it.
      \calculateleaderparameters
      \leavevmode#1\mybreak{\itshape#2\/}%
      {\setbox\scratchbox=\hbox{#2}%
      \ifdim\wd\scratchbox=0pt \kern-\dotwidth\fi}%
      \parfillskip=0pt \finalhyphendemerits=0 \par
    }%
  }%
}

\setlength{\parindent}{0pt}
\setlength{\parskip}{3pt plus 2pt}

\begin{document}

\setbox\textbox\vbox{%
\begin{multicols}{2}
    \itemlex{}{}\par
    \itemlex{un mot court}{a short word}\par
    \itemlex{un mot beaucoup plus long}{a much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus plus long}{a much much much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus long}{a much much much much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus}{muchlo much much much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus long}{a much much much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus plus long}{mucho much much longer word word word}\par
    \itemlex{un mot beaucoup beaucoup plus plus long}{mucho much much longer word word word word}\par
    \itemlex{un mot beaucoup beaucoup plus plus long}{mucho much much longer word word word word mucho much much longer word word word word ybjj}\par
    \itemlex{lorem}{lorem}\par
    \itemlex{ipsum}{ipsum}\par
    \itemlex{dolor}{dolor}\par
    \itemlex{sit}{sit}\par
    \itemlex{amet}{amet}\par
    \itemlex{{\bfseries There will be at least four dots:}}{}\par
    \itemlex{test}{1234567890123456789012345}\par
    \itemlex{test}{12345678901234567890123456}\par
    \itemlex{1234567890123456789012}{test test}\par
    \itemlex{12345678901234567890123}{test test}\par
    \itemlex{1234567890123456789012}{test test test}\par
    \itemlex{}{}\par
    \itemlex{}{}\par
    \itemlex{}{}\par
\end{multicols}%
}%

\setbox\gridbox\vbox{%
  \begingroup
  \color[RGB]{242, 242, 242}%
  \begin{multicols}{2}%
  \calculateleaderparameters
  \leavevmode 
  \leaders
    \hbox to\leaderboxwidth{%
      \kern.5\dimexpr\dotwidth-.4pt\relax
      \vrule height\dimexpr\ht\textbox-2\multicolsep\relax
             depth \dimexpr\dp\textbox+\dp\strutbox\relax
      \hss
      \rlap{%
        \kern.5\dimexpr\dotwidth-.4pt\relax
        \vrule height\dimexpr\ht\textbox-2\multicolsep\relax
               depth \dimexpr\dp\textbox+\dp\strutbox\relax
      }%
    }%
  \hfill\null
  \par
  \leavevmode 
  \leaders
    \hbox to\leaderboxwidth{%
      \kern.5\dimexpr\dotwidth-.4pt\relax
      \vrule height\dimexpr\ht\textbox-2\multicolsep\relax
             depth \dimexpr\dp\textbox+\dp\strutbox\relax
      \hss
      \rlap{%
        \kern.5\dimexpr\dotwidth-.4pt\relax
        \vrule height\dimexpr\ht\textbox-2\multicolsep\relax
               depth \dimexpr\dp\textbox+\dp\strutbox\relax
      }%
    }%
  \hfill\null
  \par
  \end{multicols}
  \endgroup
}%

\leavevmode\box\gridbox\hskip-\wd\textbox\box\textbox

\end{document}

在此处输入图片描述

这是一个省略了绘制网格的所有内容的示例:

\documentclass{article}

\usepackage{multicol}

\newlength\leaderboxwidth
\newlength\dotwidth
\newlength\minimumleaderboxwidth
\newbox\scratchbox
\newcommand\calculateleaderparameters{%
  \settowidth\dotwidth{.}%
  \setlength\minimumleaderboxwidth{.44em}%
  \setlength\leaderboxwidth{%
    \dimexpr
      \numexpr(\hsize-\dotwidth)/(%
        ((\hsize-\dotwidth)/\minimumleaderboxwidth)%
        \ifnum
          \numexpr((\hsize-\dotwidth)/\minimumleaderboxwidth)*(\hsize-\dotwidth)\relax>\numexpr\hsize-\dotwidth\relax
          -1%
        \fi
      )\relax
    sp\relax
  }%
}%

\newcommand*\Dotfillleaders{\leaders\hbox to\leaderboxwidth{.\hss\rlap{.}}}
\newcommand*\mybreak{%
  \unskip
  \nobreak
  \Dotfillleaders\hskip2\leaderboxwidth\nobreak
  \Dotfillleaders\hfil
  \penalty 0 \hfilneg
  \null\nobreak
  \Dotfillleaders\hskip\the\dimexpr2\leaderboxwidth\relax plus 1fil\nobreak
  \null\nobreak\kern\dotwidth\nobreak
}


\csname @ifdefinable\endcsname\itemlex{%
  \def\itemlex#1#2\par{%
    {%
      % The command \calculateleaderparameters can be
      % moved into the multicols-environment instead of 
      % calculating the same things again and again with each instance 
      % of \itemlex. If you do that, \calculateleaderparameters
      % needs to be called within the multicols-environment right
      % after beginning it.
      \calculateleaderparameters
      \leavevmode#1\mybreak{\itshape#2\/}%
      {\setbox\scratchbox=\hbox{#2}%
      \ifdim\wd\scratchbox=0pt \kern-\dotwidth\fi}%
      \parfillskip=0pt \finalhyphendemerits=0 \par
    }%
  }%
}

\setlength{\parindent}{0pt}
\setlength{\parskip}{3pt plus 2pt}

\begin{document}

\begin{multicols}{2}
    \itemlex{}{}\par
    \itemlex{un mot court}{a short word}\par
    \itemlex{un mot beaucoup plus long}{a much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus plus long}{a much much much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus long}{a much much much much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus}{muchlo much much much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus long}{a much much much longer word}\par
    \itemlex{un mot beaucoup beaucoup plus plus long}{mucho much much longer word word word}\par
    \itemlex{un mot beaucoup beaucoup plus plus long}{mucho much much longer word word word word}\par
    \itemlex{un mot beaucoup beaucoup plus plus long}{mucho much much longer word word word word mucho much much longer word word word word ybjj}\par
    \itemlex{lorem}{lorem}\par
    \itemlex{ipsum}{ipsum}\par
    \itemlex{dolor}{dolor}\par
    \itemlex{sit}{sit}\par
    \itemlex{amet}{amet}\par
    \itemlex{{\bfseries There will be at least four dots:}}{}\par
    \itemlex{test}{1234567890123456789012345}\par
    \itemlex{test}{12345678901234567890123456}\par
    \itemlex{1234567890123456789012}{test test}\par
    \itemlex{12345678901234567890123}{test test}\par
    \itemlex{1234567890123456789012}{test test test}\par
    \itemlex{}{}\par
    \itemlex{}{}\par
    \itemlex{}{}\par
\end{multicols}%

\end{document}

在此处输入图片描述

答案3

您可以使用下面的代码。这个想法是添加一个收缩空间和一个额外的拉伸“点填充”,当它们都在一行上时,它们会相互抵消。此外,我插入了一些惩罚,以确保换行只发生在这两个跳过之间。这意味着,如果行很长,那么第一个收缩空间会停留在换行符之前(并被 TeX 换行算法丢弃),第二个拉伸“点填充”会移动到第二行并显示出来。我必须将其设置\parfillskip为零,以确保最后一行末尾没有间隙。而且我必须使用有限收缩和/或拉伸跳过,因为 TeX 禁止在段落中使用无限收缩。这种特定方法的一个小问题是未满的水平盒子它出现在第二行的开头,但它是无害的。

\documentclass{article}

\usepackage{multicol}

\newcommand{\itemlex}[2]{%
  \parfillskip=0pt
  \mbox{#1} \dotfill\hskip0pt minus1pt{}\penalty10\hbox{}\nobreak\leaders\hbox to 0.44em{.}\hskip 0pt plus1pt \nobreak\mbox{\itshape #2}%
\par}

\setlength{\parindent}{0pt}
\setlength{\parskip}{3pt plus 2pt}

\begin{document}

\begin{multicols}{2}
    \itemlex{un mot court}{a short word}
    \itemlex{un mot beaucoup plus long}{a much longer word}
    \itemlex{lorem}{lorem}
    \itemlex{ipsum}{ipsum}
    \itemlex{dolor}{dolor}
    \itemlex{sit}{sit}
    \itemlex{amet}{amet}
\end{multicols}

\end{document}

结果: 在此处输入图片描述

相关内容