\\ 如何抑制虚假空格,而 \par\noindent 却不抑制

\\ 如何抑制虚假空格,而 \par\noindent 却不抑制

我正在尝试使用宏来构建带标题行的描述列表。在非 MWE 中,宏会添加索引条目和边注等附加值,但这里我的情况是最简单的。

\documentclass{article}
\newcommand{\pni}[1]{\item{#1} The name of the rose\par\noindent}
\newcommand{\dbs}[1]{\item{#1} The name of the rose\\}
\begin{document}
\begin{description}
\dbs{abc def}
A book that isn't about roses.

Another paragraph
\pni{abc def}
A book that isn't about roses, either.

Another paragraph
\pni{abc def}%
A book that isn't about roses, either.

Another paragraph\end{description}
\end{document}

描述项的第一行由关键字和标题组成;其余部分是段落中的描述性文本。

现在,我认为从语义上讲,使用 来\par\noindent准备文本的第一段会更好,因为这将遵循段落的“其他定义”,而不是\\,后者只是一个换行符。但正如您所见,\par\noindent在新段落的开头引入了一个虚假的空格。

在此处输入图片描述

我知道我可以通过%在我的调用中添加来抑制这种情况,但我更愿意在宏内执行此操作。怎么做?


根据迄今为止的答案(感谢并向@DavidCarlisle和@egreg致歉),这是第二个更准确反映我的情况的MWE。我正在使用enumitemmemoir我现在看到它使我的原始MWE有点过于简单化。如下:

\documentclass{memoir}
\usepackage{tgpagella}
\usepackage{xparse}
\usepackage{enumitem}
\newlist{mfields}{description}{1}
\setlist[mfields]{%
    font=\bfseries\scshape,leftmargin=!,labelwidth=3.5em,
    labelsep=0.5em,itemindent=0pt,listparindent=\parindent}
\DeclareDocumentCommand{\mfield}{m m}{%
    \item[#1]#2\par}
\DeclareDocumentCommand{\xfield}{m m}{%
    \item[#1]#2\par\noindent\ignorespaces}
\begin{document}
\begin{mfields}
\mfield{abcdef}{The Name of The Rose}
A book that isn't about roses.

Another paragraph goes here etc.

\xfield{ghijkl}{The Island of the Day Before}
A book that isn't about roses, either.

Another paragraph goes here etc.

\xfield{mnopqr}{The Island of the Day Before}

A book that isn't about roses, either.

Another paragraph goes here etc.
\end{mfields}
\end{document}

答案1

TeX 换行算法的一个基本特性是,行首的粘连(包括空格的粘连)会被丢弃。但由于段落\noindent已经开始,因此后面的空格标记会产生不会被丢弃的粘连(因为它不在换行符后面)。

看起来你The name of the rose应该成为列表标签的一部分(可选参数\item),而不是在它之后强制中断。


如评论中所述,\par\noindent如果命令后面有一个空白行,则会产生生成虚假空段落的不良影响,并且 \par\noindent\ignorespaces无法解决此问题。但是在这种情况下,无论如何您都有 0pt 缩进,因此更简单的定义是

\newcommand{\pni}[1]{\item{#1} The name of the rose\par}

空格标记和空白标记将被忽略,\par并且段落将以 0 宽度缩进开始。

或者如果\listparindent不是 0

\newcommand{\pni}[1]{\item{#1} The name of the rose\par\bgroup\parindent\z@\everypar{\egroup}}

答案2

无论何时,在带有参数的宏末尾使用\noindent(或\indent),最好添加\ignorespaces:您看到的空格是由于 之后的行尾引起的\pni{abc def}

所以

\newcommand{\pni}[1]{\item{#1} The name of the rose\par\noindent\ignorespaces}

就是答案。

为什么这种情况不会发生\\?因为这个宏有一个*变体(和一个可选参数,它本身就足够了)和查找*吃掉的空格。在这种情况下,它无论如何都不会产生任何影响,因为空格位于行的开头。


关于新的例子,如果您想要的是两个\xfield项目给出相同的结果,也就是说,在第二个项目中忽略空行,您可以定义一个\ignorespacesandpars命令来代替\ignorespaces

\makeatletter
\newcommand{\ignorespacesandpars}{%
  \@ifnextchar\par{\@ignorespacesandpars}{}}
\long\def\@ignorespacesandpars#1{\noindent\ignorespacesandpars}
\makeatother

空格会被吃掉\@ifnextchar,而\partoken 则会在去掉之后再次调用自身\par

相关内容