我们可以使用截短包截断一段文本以便它适合例如 5 厘米宽的盒子。
但是,该包只能处理一行文本。
如果我有一个(可能很长的)文本,我想将其排版在 5 厘米宽的小页面中,右边参差不齐,以便它最多使用 6 行?
基本上,我只想让 LaTeX 排版一段文本,以便我们像往常一样最多添加 5 次换行符,然后根据需要截断最后一行(使用某种截断标记,如“...”)。
我知道这对于正确对齐的文本来说很难实现,但对于右边不整齐的文本来说这可能是可行的?
编辑:为了澄清起见,如果文本被截断,我想生成如下输出:
Lorem ipsum dolor sit amet,
consectetur adipiscing
elit, sed do eiusmod tempor
incididunt ut labore et
dolore magna aliqua. Ut
enim ad minim veniam, ...
(截断标记是最后一行的一部分,而不是单独的一行。)
答案1
根据我在这里的回答:是否有一个包可以截断超出固定宽度和高度的文本?
我介绍\trunclines{<lines>}{<width>}{<content>}
如何制作给定宽度和给定文本行的截断完全对齐的框加省略号。
\documentclass{article}
\usepackage{trimclip,lipsum,stackengine}
\newcommand\trunclines[3]{%
\setbox0=\hbox{\parbox[t]{#2}{\strut#3}}%
\stackengine{0pt}{\clipbox{0pt \dimexpr\dp0-#1\baselineskip%
-\dp\strutbox+\baselineskip\relax%
{} 0in 0pt}{\copy0}}{...\strut}{U}{l}{F}{F}{S}%
}
\begin{document}
\textsf{original text in 5cm wide parbox}\smallskip
\parbox{5cm}{\lipsum[4]}\bigskip
\textsf{5cm wide parbox, truncated to 8 lines + ellipsis}\smallskip
\trunclines{8}{5cm}{\lipsum[4]}\bigskip
\textsf{or 3 lines, ragged right}\smallskip
\trunclines{3}{5cm}{\raggedright\lipsum[4]}
\end{document}
答案2
这是所有基于 e-TeX 的编译器的简单版本,它定义了一个命令\shortvbox{number of lines}{width}{text}
。这个想法基于第 5.9.6 节中描述的垂直框剖析算法TeX 按主题分类。
第一步是照常在\vbox
给定宽度的 a 中设置框文本(实际上\vtop
使用 a 来将框对齐到其第一行而不是最后一行,但这并不重要)。请注意,这也允许设置完全对齐的文本。接下来是两次运行解剖命令\shortvbox@
。该命令运行一个循环,在每次迭代时检查添加到 vbox 的最后一个节点。为此,我们使用 e-TeX 命令,\lastnodetype
它会给我们一个数字,指示哪种节点是当前列表中的最后一个节点(hbox、glue、penalty 等)。根据节点类型,我们使用适当的命令来移除并稍后重新组装最终的框。
如上所述,这里需要两次运行。这是因为我们从下往上遍历框,但需要第一次n最终输出的框的行数。因此,在第一次运行(由参数指示C
)时,我们仅计算列表中出现的行数/水平框数并跳过重新组装。在第二次运行中,我们实际上重新组装了垂直框,现在倒着计算行数。跳过最终输出中所需行数之后出现的所有行,其他行将添加到结果框中。最后一步是输出重新组装的框,并\ldots
在末尾添加一些行。
完整示例代码:
\documentclass{article}
\usepackage{lipsum}
\makeatletter
\endlinechar=-1
\newcount\shortvbox@lines
% #1: Number of lines in the final box
% #2: Width of the box
% #3: Text
\long\def\shortvbox#1#2#3{
\begingroup
\setbox0=\vtop{\hsize=#2 #3\par}
\setbox2=\vtop{\unvcopy0\shortvbox@{#1}C}
\setbox2=\vtop{\unvcopy0\shortvbox@{#1}B}
\vtop{\hsize=#2\unvbox1\par\noindent\strut\ldots\par}
\endgroup
}
% #1: number of lines to reassemble
% #2: C = count lines only, otherwise also build box
\def\shortvbox@#1#2{
\begingroup
\global\setbox1=\vtop{}
\if#2C
\global\shortvbox@lines=0\relax
\fi
\loop
\count1=\lastnodetype
\ifnum\count1=1\relax % hbox
\setbox10=\lastbox
\global\advance\shortvbox@lines by \if#2C 1\else -1\fi
\fi
\ifnum\count1=11\relax % glue
\skip10=\lastskip
\unskip
\fi
\ifnum\count1=13\relax % penalty
\count10=\lastpenalty
\unpenalty
\fi
% \message{lastnodetype=\the\count1}
\edef\@stop{
\ifnum\count1<0 0\else
\ifnum\count1=1 1\else
\ifnum\count1=11 1\else
\ifnum\count1=13 1\else
0% stop early if we don't know how to handle the last node
\fi\fi\fi\fi
}
\if\@stop0
\else
\if#2C\else
\global\setbox1=\vtop{
\ifnum\shortvbox@lines<#1\relax
\ifnum\count1=1\relax % hbox
\box10
\fi
\ifnum\count1=11\relax % glue
\vskip\skip10
\fi
\ifnum\count1=13\relax % penalty
\penalty\count10
\fi
\unvbox1
\fi
}
\fi
\repeat
\endgroup
}
\endlinechar=`\^^M
\makeatother
\begin{document}
\fbox{\shortvbox{7}{5cm}{What if I have got a (possibly long) text that I would like to typeset in a 5cm wide minipage, \textbf{ragged right}, so that it uses at most 6 lines?
\vskip2ex
Basically, I would just like to ask \LaTeX to typeset a piece of text so that we add line breaks as usual at most 5 times, and then the last line is truncated (with some kind of a truncation marker such as \texttt{"..."}) if needed.}}
\hskip1em
\fbox{\shortvbox{4}{5cm}{\raggedright What if I have got a (possibly long) text that I would like to typeset in a 5cm wide minipage, \textbf{ragged right}, so that it uses at most 6 lines?
\vskip2ex
Basically, I would just like to ask \LaTeX to typeset a piece of text so that we add line breaks as usual at most 5 times, and then the last line is truncated (with some kind of a truncation marker such as \texttt{"..."}) if needed.}}
\shortvbox{4}{\linewidth}{\lipsum}
\end{document}
这个版本应该更像是一个概念验证实现。例如,在当前版本中,它仅适用于简单的文本段落。当然,可以添加更多节点类型。另一件事是连字符可能出现在最后一行之前。我想摆脱它需要更多的努力。