挤压段落,使行宽相近

挤压段落,使行宽相近

我想格式化一段文本,使得段落的宽度缩小直到段落的最后一行与所有其他行的宽度大致相同。

下面是我的意思的一个例子CSS/JavaScript

在 LaTeX 中,考虑以下文档:

\documentclass{article}

\begin{document}

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam justo sem, 
malesuada ut ultricies ac.

\end{document}

对我来说,这会产生两行,在“sem,”之后有中断,因此第二行明显短于第一行:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam justo sem, 
malesuada ut ultricies ac.

我想要的是这样的(尽管换行符的具体位置取决于字体):

Lorem ipsum dolor sit amet, consectetur adipiscing 
elit. Nam justo sem, malesuada ut ultricies ac.

任何指导都将不胜感激,因为我自己无法取得任何进展。我知道我可以使用\parbox\minipage来制作固定宽度的段落,但这需要动态宽度。

答案1

该版本应该可以工作,尽管有时它可能会产生溢出\hbox错误。

\documentclass{article}

\newcommand{\squeeze}[1]% #1 = paragraph
{\bgroup
  \sbox0{#1}% get total width
  \setbox1=\vbox{\strut #1\strut}% get paragraph height
  \dimen0=\dimexpr \ht1 + \dp1\relax
  \count1=\numexpr \dimen0 / \baselineskip\relax% number of lines in paragraph
  \dimen0=\dimexpr \wd0 / \count1\relax% divide total width by number of lines
  \parbox[b]{\dimen0}{\parfillskip=0pt
    \strut #1\strut}%
\egroup}

\begin{document}

\squeeze{Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam justo sem, 
malesuada ut ultricies ac.}

\end{document}

演示


此版本以循环方式增加宽度,直到文本能够适应正常的宽度\parfillskip

\documentclass{article}

\newcommand{\squeeze}[1]% #1 = paragraph
{\bgroup
  \sbox0{#1}% get total width
  \setbox1=\vbox{\strut #1\strut}% get paragraph height
  \dimen0=\dimexpr \ht1 + \dp1\relax
  \count1=\numexpr \dimen0 / \baselineskip\relax% number of lines in paragraph
  \dimen0=\dimexpr \wd0 / \count1\relax% divide total width by number of lines
  \loop
    \sbox0{\parbox[b]{\dimen0}{\strut #1\strut}}%
    \ifdim\ht0>\ht1
    \advance\dimen0 by 1pt
    %loop\par% display number of steps
  \repeat
  \parbox[b]{\dimen0}{\parfillskip=0pt
    \strut #1\strut}%
\egroup}

\begin{document}

\squeeze{Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam justo sem, 
malesuada ut ultricies ac.}

\end{document}

在这种情况下,生成的矩形仅比以前宽 2pt。

演示2

答案2

我调整了约翰发布的算法来解决我在我的文档中遇到的一些特殊情况(其中有数百个这样的“挤压”段落)。

John 的算法都是从计算段落中行的平均宽度开始的。没有循环的算法就此停止,只是让段落达到平均宽度。我发现这种简单的启发式方法经常会产生错误的结果。然后,带有循环的算法会增加段落的宽度,直到段落中的行数不超过开始时的行数。这种方法更可靠,但也倾向于产生明显比页面宽度更宽的段落。

我的算法从段落的自然宽度开始,然后使其越来越窄,直到被迫换行。这种方法对我的所有用例都很有效。我还将文本居中并禁用连字符,因为这是我想要的样式,但这很容易改变。

\documentclass{article}

\usepackage{etoolbox}
\usepackage{hyphenat}

\newcommand{\squeeze}[1]%
{\bgroup

  % Make a natural-size box for the paragraph.  Note the initial width and 
  % height of the paragraph.
  \setbox0=\vbox{\centering \nohyphens{#1}}
  \dimen0=\wd0
  \dimen1=\dimexpr \ht0 + \dp0

  % Keep making the box narrower and narrower until it the text spills onto 
  % another line.  Use a generous threshold (\baselineskip / 2) for deciding 
  % when another line has been used, because the box can change height slightly 
  % as words move around.
  \dimen2=\dimexpr \dimen1 + \baselineskip / 2\relax
  \whileboolexpr{
    test {\ifdimless{\dimen1}{\dimen2}}
    and
    % Without this test, trying to squeeze a single word would cause an 
    % infinite loop.
    test {\ifdimgreater{\dimen0}{0pt}}
  }{
    \advance\dimen0 by -1pt\relax
    \sbox0{\parbox{\dimen0}{\centering \parfillskip=0pt \nohyphens{#1}}}
    \dimen1=\dimexpr \ht0 + \dp0
  }

  % Go back the previous width (i.e. the minimum width without spillover).  
  \advance\dimen0 by 1pt\relax
  \parbox{\dimen0}{\centering \parfillskip=0pt \nohyphens{#1}}

\egroup}

\begin{document}

\squeeze{Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam justo sem, 
malesuada ut ultricies ac.}

\end{document}

声明一下,这是我第一次用 TeX 基元编程,所以我真的不知道自己在做什么。我也非常感谢 John 提供了一些可供我参考的工作代码。

相关内容