在LaTeX中定义宏的正确方式,如\etc和\ie。

46
这篇文章中,作者讨论了使用“\ @”来在句子结尾不是完整句子的情况下(例如Mr. ,ie等)正确地添加空格的方法。
所建议的宏
\newcommand\etc{etc\@ifnextchar.{}{.\@}}

这个方法并不完美,因为在(\etc more text)的情况下,它会生成(etc.more text)

我见过很多作者自己制作了自己的版本\etc宏,大多是变形的etc.\

对于\etc\ie\etal\eg这些宏,哪些能在大多数情况下产生最好的效果?

这是一些太过于个人口味以至于无法一般化解决的问题吗?


这是我长时间以来最喜欢的SO [latex] qn。 - Charles Stewart
2
我在我的类似于\etc的宏中使用了\xspace,看着它,我发现它给了我错误的间距,而我从未注意到。我很高兴读到这个问题。 - Ivan Andrus
@Ivan - 有哪些反例?我几天前发布了一个答案,刚看到这个评论。 - Geoff
抱歉,我的表述不够清晰。我使用了etc.\xspace而不是etc.@\xspace,这自然会导致问题。 - Ivan Andrus
在 tex.stackexchange 上有相关问题:间距的良好实践 - Charles Stewart
@CharlesStewart 这个问题是否应该完全迁移到tex.SE? - Jonathan H
5个回答

27

我以前使用宏定义“et al.”等内容,但现在我不建议人们定义这种宏。

问题之一是你已经发现的:想要正确处理所有特殊情况(包括与其他软件包交互的情况,例如重新定义"\cite"命令并在参考文献前调整间距)非常困难。

但更重要的是,即使有一堆适合你需要且你知道如何使用的宏,你的合作者也可能会在各种特殊情况下被困扰,不知道如何正确使用你的宏。

因此,我建议您避免使用像“et al.”这样的微不足道的事物的宏定义,并通过使用标准的Latex标记来拼写所有内容。毕竟,大多数情况不需要任何特殊处理(例如,“e.g.”通常后面跟着逗号;“et al.”通常后面跟着“~\cite”等),每当需要特殊处理时,所有Latex用户都应该知道如何使用"\ "和"\ @"等命令。


1
我同意你回答中“治疗比疾病更糟”的观点,但是“所有的Latex用户都应该知道如何使用命令,例如"\ "和"@"”让我迷惑了:你知道Tex在".)"后面放置额外的空格吗?如果是的话,恭喜你成为精英TeX技术员。如果不知道,那么你就不知道@的正确用法,这也是引发问题的原因。TeX消化你的文本的方式非常棘手,足以让像Will Robertson这样的人陷入困境。 - Charles Stewart
查尔斯:哦,抱歉,我指的是更简单(也更常见)的情况,这些情况在任何Latex教程中都有涵盖。当然,我同意“.)”这种情况确实令人惊讶,从原始问题中学到了新东西,这很好。 :) 然而,我认为像这样的复杂性是不应该尝试使用宏来修复的一个很好的理由... - Jukka Suomela
1
似乎这是最好的方法(至少在 LaTeX3 成为标准之前)。 - Niall Murphy
+1. Charles刚指出了一个非常重要的情况,让我认为这个答案是正确的 -- 当缩写结束一个句子时。你怎么处理这个问题?有没有一种单一的宏或任何智慧可以告诉我们这个句号是否结束了一个句子? - Geoff
1
@Geoff:这个网站包含一些LaTeX技巧,并简要评论了宏和空格问题。作者提到了xspace包,他认为这是一种“启发式方法,用于打败LaTeX在宏后面吞噬空格的行为,在输出中保留空格的情况下”。我没有仔细阅读,因为我只是简单地浏览了该网站并且有其他原因,但它可能会对你有所帮助,或者至少我希望如此。问候。 - Throoze

17

在CVPR的样式包中,它被定义为:

\usepackage{xspace}

% Add a period to the end of an abbreviation unless there's one
% already, then \xspace.
\makeatletter
\DeclareRobustCommand\onedot{\futurelet\@let@token\@onedot}
\def\@onedot{\ifx\@let@token.\else.\null\fi\xspace}

\def\eg{\emph{e.g}\onedot} \def\Eg{\emph{E.g}\onedot}
\def\ie{\emph{i.e}\onedot} \def\Ie{\emph{I.e}\onedot}
\def\cf{\emph{c.f}\onedot} \def\Cf{\emph{C.f}\onedot}
\def\etc{\emph{etc}\onedot} \def\vs{\emph{vs}\onedot}
\def\wrt{w.r.t\onedot} \def\dof{d.o.f\onedot}
\def\etal{\emph{et al}\onedot}
\makeatother

6
你尝试过使用xspace包吗?
示例宏:
\def\etc{etc.\@\xspace}

一些测试:

Cat, dog, \etc. And so on.   \\
Cat, dog, \etc! And so on.   \\
Cat, dog, \etc, and so on.   \\
Cat (dog, \etc). And so on.  \\
产生:

alt text


来自文档

xspace包提供了一个单一的命令,它查看命令流中它后面的内容,并决定是否插入一个空格来替换TeX命令解码器吃掉的空格。


3
在你的第一个测试中,你需要吞掉缩写词中的句号(即不是“等等..”),因此你需要同时测试下一个字符。但你是正确的,可以使用xspace包代替显式地测试catcode 10。 - Charles Stewart
哦,哇,好观点。所以第一个例子是错误的。我不知道这个语法规则。 - Geoff
所以,在你的例子中,Maybe a list, \eg, 应该是 Maybe a list, \eg., 因为你的宏里没有结尾的句号。我现在明白为什么你不在宏里包含结尾的句号了。谢谢。 - Geoff
1
我查阅的所有关于句末缩写的指南都明确禁止第一种情况,例如Butcher(2009)在《编辑清单》中将其列为“常见的标点错误”之一。第二种情况有问题:我会将“.!”缩写为“!”,但我不知道是否有任何指南规定必须这样做。我的代码没有处理这种情况。 - Charles Stewart

5

一项技术挑战!我们可以通过查看下一个字符的catcode来避免空格后的字母问题;这可以使用Latex3的expl3宏\peek_charcode:NTF来实现(我的第一个expl3代码!):

\documentclass{article}

\usepackage{expl3}
\ExplSyntaxOn
\newcommand\latinabbrev[1]{
  \peek_meaning:NTF . {% Same as \@ifnextchar
    #1\@}%
  { \peek_catcode:NTF a {% Check whether next char has same catcode as \'a, i.e., is a letter
      #1.\@ }%
    {#1.\@}}}
\ExplSyntaxOff

%Omit final dot from each def.
\def\eg{\latinabbrev{e.g}}
\def\etal{\latinabbrev{et al}}
\def\etc{\latinabbrev{etc}}
\def\ie{\latinabbrev{i.e}}

\begin{document}

Maybe a list, \eg, a, b, c, and d.  Which is to say (\ie) a, b, \etc.  Consider Knuth, \cf The TeXbook.

\end{document}

Jukka的建议我认为很有道理:我认为Will在他的\etc宏中解决的问题应该被视为Tex实现双倍行距的bug(Will Robertson应该要求支票):如果你知道这个bug存在,你可以通过在".)"等情况下加入\@来直接解决它,或者你可以编写一些棘手的代码,这样你就不必在这种情况下思考,但是你已经增加了排版的复杂性,这对于下一个意外的故障不起作用,可能是你自己引入的。

附言 之前的版本已经修复,感谢Joseph Wright在tex.stackexchange.com上注意到了一个愚蠢的错误。


1
它是“et al.”,缩写形式为“et alii”。 - Svante
此外,我认为在“i.e.”和“e.g.”中应该有一个小的、不可打破的空格。 - Svante
@Charles Stewart:我不是完全确定,但我认为实际上应该是“i.e.”。人们不希望在换行处断开它,因此在“计算机文本”中将其键入为“i.e.”已成为惯例,但在TeX中,最好使用“i.~e.”。缩小这个空格可能是个好主意,但完全消除它看起来不太对。 - Svante
我认为Tex处理“.)”的方式(严格来说)并不是一个bug。(考虑一下括号注释——像这样——它由几个句子组成,并以句号结束。如果在右括号后添加额外的空格,我认为Tex做得很对。)话虽如此,我想如果Tex不尝试猜测任何东西,而只是有一个特殊的标记表示句子的结尾,那么我会更加高兴,但现在改变已经有点太晚了... - Jukka Suomela
1
@Charles:TeX将其排版为“closing_parenthesis.)That_said”,而不是“closing_parenthesis.)_That_said”。 - Jukka Suomela
显示剩余7条评论

0
所有LaTeX命令都会在其后消除空格。如果您需要一个空格,您需要对其进行转义:
\etc\ and more

这是必要的,因为你需要清楚命令名称的结束位置。 \etc无空格 无法正确解释。

但是你可以向前查看,以查看下一个字符是否为catcode 10,以查看是否应该有一个空格:请参见我的答案。 - Charles Stewart
1
很抱歉一直挑剔:实际上并不是所有命令都会消除空格:只有由字母组成的命令(即,类别码为10的字符)才会。以正常方式定义的其他命令(即,不使用\csname)是一个字符长的控制序列,不会吞噬空格。这正是为什么查看下一个字符的类别码是个好主意的原因。 - Charles Stewart
我发现了一个名为 xspace 的包,它可以检查你是否需要空格。你能否看一下我的答案,看看是否有任何反例?谢谢。 - Geoff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接