宏的简称

宏的简称

我经常会想定义一些宏来使用非常在整个文档中经常出现 – 例如,我在许多方程式中反复使用的一个特殊符号。

理想情况下,在这种情况下,我希望宏的名称尽可能短。但是,大多数单字母名称似乎已经定义,要么在标准 Latex 类中,要么在常用包中。例如, 、、 、 、 、 、 、\b\c已经\d定义\i\j通常\l\o只是放弃并使用类似的东西来代替以避免冲突,但它有点冗长。\t\u\v\myX\X

两个问题:

  1. 是否有一个非常短的名字列表可用的并且我可以(合理安全地)将其用于我自己的目的?

  2. 是否有一些巧妙的技巧和窍门可用于定义宏的短名称?例如,该babel包使"字符变得特殊,以便您可以使用诸如"=和之类的序列"a来输入符号。我是否可以为自己的目的使用类似的技巧,使用另一个字符代替"- 或者它是唯一尚未分配的字符?

我想坚持使用简单的 7 位 ASCII 字符。

答案1

您可以使用以下命令显示此单字母宏的定义:

$ texdef -t latex a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

texdef命令在 CTAN 上可用。

其中大多数似乎都是变音符号。参见https://en.wikibooks.org/wiki/LaTeX/Special_Characters一张桌子。

以下是上述内容的格式化后的输出texdef

Undefined:
\e \f \g \h \m \n \p \q \s \w \x \y \z
\A \B \C \D \E \F \G \I \J \K \M \N \Q \R \T \U \V \W \X \Y \Z

\a:
macro:#1->\expandafter \@changed@cmd \csname \string #1\endcsname \relax 
\b:
macro:->\OT1-cmd \b \OT1\b 
\c:
macro:->\OT1-cmd \c \OT1\c 
\d:
macro:->\OT1-cmd \d \OT1\d 
\i:
macro:->\OT1-cmd \i \OT1\i 
\j:
macro:->\OT1-cmd \j \OT1\j 
\k:
macro:->\T1-cmd \k \T1\k 
\l:
macro:->\OT1-cmd \l \OT1\l 
\o:
macro:->\OT1-cmd \o \OT1\o 
\r:
macro:->\OT1-cmd \r \OT1\r 
\t:
macro:->\OML-cmd \t \OML\t 
\u:
macro:->\OT1-cmd \u \OT1\u 
\v:
macro:->\OT1-cmd \v \OT1\v 
\H:
macro:->\OT1-cmd \H \OT1\H 
\L:
macro:->\OT1-cmd \L \OT1\L 
\O:
macro:->\OT1-cmd \O \OT1\O 


\P:
macro:->\protect \P  
\P :
\long macro:->\ifmmode \mathparagraph \else \textparagraph \fi 


\S:
macro:->\protect \S  
\S :
\long macro:->\ifmmode \mathsection \else \textsection \fi 

答案2

概括。这个答案(我已经在几次迭代中对其进行了扩展)描述了如何采用单个字符(例如"),使其处于活动状态,并使用它来生成替代的单字符控制序列(例如"a),其行为与正常控制序列非常相似。


(#1)重新利用典型的非字母字符。如果您没有使用任何"为其自身目的而重新定义的包,则可以使用它来为宏定义备用命名空间,如下所示。

\makeatletter

   \catcode`\"=13

   \def"#1{\csname @mymacro#1\endcsname}

   \def\newmacro"#1{%
       \@ifnextchar [{%
           \expandafter\newcommand\csname @mymacro#1\endcsname
        }{%
            \expandafter\def\csname @mymacro#1\endcsname{%
                \csname @@mymacro#1\endcsname\ignorespaces}%
            \expandafter\newcommand\csname @@mymacro#1\endcsname
        }}

   \def\renewmacro"#1{%
       \@ifnextchar [{%
           \expandafter\renewcommand\csname @mymacro#1\endcsname
        }{%
            \expandafter\def\csname @mymacro#1\endcsname{%
                \csname @@mymacro#1\endcsname\ignorespaces}%
            \expandafter\renewcommand\csname @@mymacro#1\endcsname
        }}

\makeatother

这样做的目的是" 积极的(解释为单字符控制序列),然后为其提供一个定义,该定义导致"a"q(例如)分别调用控制序列\@mymacroa\@mymacroq。宏\newmacro和提供了一个简单的接口,\renewmacro用于定义使用字符调用的宏",语法为\newmacro"a{...},,\renewmacro"q{...}ETC。使用类似于\newcommand和的语法\renewcommand,包括您想要的任何(可选)参数。我们在定义宏时执行一些额外的测试,以检查它们是否接受参数:如果没有,我们会添加一个带有尾随的额外命令层,以确保宏或(或其他)\ignorespaces之后的任何空格都被使用。"a"q

如果您需要与babel或另一个为 提供特殊含义的包进行互操作",则可能需要使用不同的字符 - 您可以自行决定使用哪个字符,尽管它应该是一个带有目录代码 12(或者如果你够大胆,一封通常有目录代码 11如果你的文档语言中有一个几乎从未使用过的字母,例如 w法语中)。也可以采用多字符解决方案(例如 例如在Christian Lindig 快速切换粗体字体的解决方案)。但是,如果您特别关心击键次数等,多字符解决方案可能会适得其反。


(#2)限制对特殊角色的重新利用。我在评论中注意到,您最感兴趣的是在数学模式下使用这些替代宏。这使我们能够利用进一步的技术。同时,有限的范围使我们可以在为此目的而篡夺的字符上更具冒险精神。

在本例中,我将展示如何使用字符实现与上述类似的效果#,该字符通常用于枚举宏的参数。我们要做的是使#活动仅在数学模式中(和显示环境),谨慎的 LaTeX 用户通常可以避免定义新的宏。这还会涉及我们实现界面的方式的一些外观差异。

\makeatletter

   \catcode`\#=13
   \catcode`\$=6
      \def#$1{\csname @mymacro$1\endcsname}
   \catcode`\$=3
   \catcode`\#=6

   \def\newmacro\##1{%
       \@ifnextchar [{%
           \expandafter\newcommand\csname @mymacro#1\endcsname
        }{%
            \expandafter\def\csname @mymacro#1\endcsname{%
                \csname @@mymacro#1\endcsname\ignorespaces}%
            \expandafter\newcommand\csname @@mymacro#1\endcsname
        }}

   \def\renewmacro\##1{%
       \@ifnextchar [{%
           \expandafter\renewcommand\csname @mymacro#1\endcsname
        }{%
            \expandafter\def\csname @mymacro#1\endcsname{%
                \csname @@mymacro#1\endcsname\ignorespaces}%
            \expandafter\renewcommand\csname @@mymacro#1\endcsname
        }}

\makeatother

\everymath=\expandafter{\the\everymath\catcode`\#=13}
\everydisplay=\expandafter{\the\everydisplay\catcode`\#=13}

前几个命令定义了角色#处于活动状态时执行的操作:IE 与前面的例子相同"。为此,我们将其#激活,并暂时将其设置$为表示宏参数的字符。然后,在继续之前,我们恢复#and的通常含义$,只是为了避免麻烦。

人们通常会在序言中定义宏,即事实本身在数学模式之外。因此,我们需要一个略有不同的语法来定义宏,\newmacro并且\renewmacro不假设处于#活动状态(更不用说可能#需要描述参数!)。最简单的方法是使用语法\newmacro\#a{something}\renewmacro\#q[1]{something},使用命令序列\#作为这些命令语法的一部分。请注意,这些命令也可以在文档正文中使用,在正常文本模式下。

最后,我们重新定义了钩子\everymath\everydisplay,每当您使用$ math mode $\[ displayed math \](包括包提供的环境amsmath)时都会调用它们,以生成#活动字符。当离开数学/显示模式时,其作为表示参数的字符的正常状态将恢复。

如果您愿意,请在包含上述代码并使用包的文档中尝试以下内容来试用此代码amsmath。这旨在演示此代码与 mathmode 以及随后的宏定义的忠实互操作性。

\begin{document}
\newmacro\#a[2]{#1 \stackrel?= #2}

$ #abc $

\begin{align}
  \begin{gathered}
            #a 1 2  \\
            #a {\mathsf{P}}{\mathsf{NP}}
  \end{gathered}
    & &
        #ask
\end{align}

\newcommand\test[2][\bfseries]{\textsf{#1 #2}}
\test{bold and sans-serif}
\test[\itshape]{italic and sans-serif}
\end{document}

(#3) 对这些技术的评论。以这种方式定义的宏的行为与普通控制序列不同,如示例#所示。具体来说,我在这里描述的机制实际上是为单字符宏名设计的。

"以我们为了讨论而激活的为例:源代码"abc将扩展为\@mymacroa bc而不是\@mymacroabc。(“宏”的名称在字符的第一个参数处停止",在本例中是a。)如果你尝试使用 定义宏\newmacro"abc{something},其效果将与编写相同

\newmacro"a{b}%
c{something}

\@newmacroabc而不是定义产生 的宏{something}

定义具有较长名称的宏,例如\newmacro"{abc},但这样做很愚蠢。或者,您可以定义"以尝试获取尽可能多的字母字符(具有 catcode 11)来构成宏的名称,就像 Bruno 在另一个答案中所做的那样。但我对此并不感兴趣,尤其是因为重点是定义替代的单字符宏。这已经是一种非标准机制;如果没有进一步的动机,人们应该在脑海中想出一个特殊情况的具体想法,当人们想要使用它时。我提出了当特殊情况是“访问极短的宏名称”时的解决方案。

答案3

我在一家学术出版商工作多年,我想说的是,在我看来,这样的宏是糟糕的麻烦。你的输入可能与它自己一致,但不会与任何其他人的一致。

但如果你因为一些(对我来说)难以理解的原因而必须定义语法宏,那么迄今为止最好的语法宏是那些实际上描述内容。这些通常不是最短的,但至少当其他人必须编辑您的文本时,输入语法会为生成的输出提供线索。例如:

A \in \Q

\Q如果是 \mathbb{Q} 则有点合理,但是

\theta \neq \Q

无论 \Q 的定义是什么,我都认为它不好。

使用活动字符而不是反冲的宏绝对是可怕的,原因大致相同:想象一下编辑别人的文件,其中像简单的 @ 符号这样的东西突然变成了宏。

次要参数:在某些工作流程中,您的实际 TeX 输入可以成为结果的一部分(例如,作为 html/epub 视图中位图的替代文本)。没有任何宏定义将保留下来,因此读者(即使是非常了解 LaTeX 的读者)也必须猜测其想要的含义。

答案4

\0,,\1...,\9通常被视为用户空间临时 csname:您可以按照自己想要的方式将它们重新用作短宏名。

您可以定义一个宏,使\let所有这些宏名都等于您在其定义中使用的长 csname,并且如果您担心某些行为不当的包正在重新利用它们,那么您可以使用另一个宏来测试与长 csname 的相等性,并且\ifx没有被违反。

相关内容