我需要一个宏来将对象与右边缘对齐,如果在文本和对象之间留有空格,则在当前行对齐,否则在下一行对齐。在后一种情况下,其他材料不应与对象出现在同一行上。
我的第一次尝试 ( \tmarksi
) 似乎有效,但如果它出现在段落末尾,则会导致水平盒子未满警告(我不明白为什么)。第二次尝试 ( \tmarksii
) 似乎插入了不必要的段落分隔符。因此,我在第三次尝试中尝试在本地设置\parskip
为零,但这也不起作用。
这当然不应该很难;我遗漏了什么?
\documentclass{article}
\setlength\parindent{0pt}
\setlength\parskip{2cm} %For illustration purposes
%
\newcommand\tmarksi[1]{\hspace*{\fill}~\mbox{[#1]}\newline}
\newcommand\tmarksii[1]{\hspace*{\fill}~\mbox{[#1]}\vskip0pt}
\newcommand\tmarksiii[1]{\hspace*{\fill}~\mbox{[#1]}\bgroup\parskip=0pt\parindent=0pt\par\egroup}
%
\begin{document}
The quick brown fox jumps over the lazy dog. \tmarksi{1}
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over \tmarksi{1}
the lazy dog.
\end{document}
答案1
您可以使用 TeXbook 中的“Bourbaki 问题”的变体
\documentclass[convert,border=2]{standalone}
\newcommand{\tmark}[1]{%
{{\unskip\nobreak\hfil\penalty50
\hskip2em\vadjust{}\nobreak\hfil[#1]%
\parfillskip=0pt \finalhyphendemerits=0 \par
\penalty 10000 \parskip=0pt\noindent}}\ignorespaces}
\begin{document}
\begin{minipage}{150pt}\parindent=20pt\parskip=20pt
The quick brown fox jumps over the lazy dog.\tmark{1}
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over\tmark{1}
the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy \tmark{1}
the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy brown dog \tmark{1}
Another
\end{minipage}
\end{document}
这引入了段落分隔符,但也存在问题\noindent
,并且\penalty 10000
会阻止分页符。我还添加了\parskip=0pt
以掩盖我们的踪迹。文本末尾和标记之间的最小间距为 2em,请尝试一下。
注意:\parskip
在中设置minipage
只是为了显示效果。还\parindent
需要设置,否则为零。
为了在标记移至下一行时使文本右对齐,将第一个改为\hfil
。\hskip0pt
为了使单词间距最小,请\hskip2em
改为\space
。
以下版本实现了这一点,并且在标记移动到下一行时也避免了分页符:
\newcommand{\tmark}[1]{%
{{\unskip\nobreak\vadjust{\nobreak}\hskip0pt\penalty50 \space
\vadjust{}\nobreak\hfil[#1]%
\clubpenalty=0 \widowpenalty=0 \brokenpenalty=0
\parfillskip=0pt \finalhyphendemerits=0 \par
\penalty 10000 \parskip=0pt\noindent}}\ignorespaces}
这是有代价的:我们对寡妇和俱乐部路线的控制较少,但正如弗兰克·米特尔巴赫在评论中所说,满足这两个必需品似乎很难。
答案2
我假设你的意思是\tmarksi
如果它位于段落末尾,则会生成一个未满的水平盒子,而不是一个过满的水平盒子。出现这种情况的原因是,该\newline
定义中的 总是在该段落中开始另一行,然后最后一行完全为空。这就是为什么在 LaTeX 中\\
或\newline
被引入为行分隔符而不是行尾(尽管许多人尝试使用\\ \\
来获取空行或额外空间)。
因此,这意味着您要么为这两种情况编写两个不同的命令,要么尝试这样的操作:
\newcommand\tmarksi[1]{\hspace*{\fill}~\mbox{[#1]}\penalty -9999 }
这里的不同之处在于,我使用的惩罚并不完全是“总是在这里中断”,因此段落末尾的最后一个断点将覆盖它。但是,在段落内,它通常就足够了,只要您不使用明确的\linebreak
命令即可。所以请自行选择。