哪些 LaTeX 宏不能接受组作为参数?

哪些 LaTeX 宏不能接受组作为参数?

我正在开发一款 LaTeX 漂亮打印机,它可以解析 LaTeX 文档,然后重新渲染源代码。(我知道这并非在所有情况下都可行,但很多时候应该是可行的。)

本着Prettier,我希望代码格式化程序具有主见,并且我正在尝试决定哪些宏应该将其参数自动包装在组 {} 中。例如,\mathbb R应该转换为\mathbb{R},并且\frac23应该转换为\frac{2}{3}

我的问题是:(a)是否存在将一组参数传入 LaTeX 宏会导致意外行为的情况?(b)是否存在将参数包装在组中视为“最佳实践”的宏?

后续问题是:您会将哪些内容放入常用的“特殊”宏列表中。这可能包括不遵循标准约定(of[...]{...}style 参数)的 LaTeX 宏,或需要特殊处理的常用宏(例如几乎所有蒂克兹环境...)。

为了控制范围,我不是尝试解析复杂的 TeX 编程或宏定义本身。

答案1


所有 TeX 宏都在其参数周围使用括号组,如果参数是单个标记,则可以省略括号组,尽管在分隔参数的情况下,该组可能不在您想要的位置。

\def\foo#1#2{...}

\foo12\foo 1 2\foo{1}{2}\foo{1} {2}都是等价的。

\def\foo(#1,#2){...}

\foo(1,2)\foo({1},{2})\foo(1,{2}), 都是等价的。


TeX 基元没有这种可选的括号。

\hbox{a} 括号是必需的,\hbox a 这是语法错误,但是括号可以是隐式的,\hbox\bgroup a}这是可以的。

\hskip 5pt 没有括号,\hskip{5pt}是语法错误

\def\foo{zzz} 定义的标记周围不能有括号,


一些记录为带参数的命令实际上并不带参数,例如,\section一个不带参数的宏只是向前查找*[在每种情况下调用适当的宏,所以

\section*[short]{l} 可以写成\section*[{short}] l但不能\section{*}[short]{l}


一些包将^和重新定义_为宏并采用如上所述的带有可选括号组的参数,但原始行为很“有趣”,因为 tex 会扩展以寻找可能隐式的括号,例如x^\mathrm xx^{\mathrm{x}}x^\frac12x^{\frac{1}{2}} 作为的第一级扩展\mathrm\frac提供{}上标所需的组。

答案2

这不是一个完整的答案,但任何使用的东西\@ifnextchar都可能引起问题。我借用\CheckMinus这个答案

\documentclass{article}
\makeatletter
\def\CheckMinus{\@ifnextchar-{got a minus}{no minus}}
\makeatother
\begin{document}
$\left(1\right)$ % works
%$\left{(}1\right{)}$ % doesn't work

\CheckMinus-

\CheckMinus{-}

\end{document}

在此处输入图片描述

答案3

相当多的 TeX“原语”采用了不能在组中分隔的参数。

  • 文本模式和数学模式字距调整命令:\kern\mkern,每个命令接受 1 个参数。

    a\kern1em a
    $a\mkern18mu a$
    

    都可以,但是a\kern{1em} a和则$a\mkern{18mu} a$不行。

  • 命令\raise\lower每个命令接受 2 个参数,其中第一个必须是长度变量,第二个必须是 (TeX) 框。

    a\raise1ex\hbox{c}
    

    是可以的,但是a\raise{1ex}\hbox{c}a\raise1ex{\hbox{c}}a\raise{1ex}{\hbox{c}}不可以。

    LaTeX 中a\raise1ex\hbox{c}is 的对应\raisebox{1ex}{c}项也接受两个参数。显然,with\raisebox是允许的 —— 并且,根据参数的不同,实际上可能是必需的。

答案4

如果宏的最后一个参数由左花括号分隔,则会出现问题。
您可以使用#{-notation 及其⟨parameter text⟩定义的 来定义此类宏。

这种宏的一个例子是\name-macro。

-macro\name用于避免\expandafter-orgies \csname..\endcsname

-macro\name处理由左花括号分隔的参数。

其定义如下:

\makeatletter
\@ifdefinable\name{%
  \long\def\name#1#{\romannumeral0\innername{#1}}%
}%
\newcommand\innername[2]{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}%
}%
\newcommand\exchange[2]{#2#1}%
\makeatother

使用方法如下:

\name⟨stuff without curly braces⟩{macroname}
⟨stuff without curly braces⟩\macroname

例如,

\name{macro}\macro
\name\newcommand{macro}...\newcommand\macro...
\name\global\long\def{macro}...\global\long\def\macro...
\name\string{macro}\string\macro
\name\meaning{macro}\meaning\macro
\name\name\global\let{macroA}={macroB}\name\global\let\macroA={macroB}\global\let\macroA=\macroB

假设⟨stuff without curly braces⟩是一个单一的标记,如下所示:

\name X{Y}X\Y

进一步假设您的漂亮打印机将 包裹X在括号组中。在这种情况下,您有:

\name {X}{Y}\X{Y}

,略有不同。


当 TeX 搜索构成带分隔符的宏参数的分隔符的标记时,它不会将嵌套在括号组中的内容作为参数分隔符,除非所讨论的宏嵌套在括号组中。

假设宏的参数由字符分隔a

\def\macro#1a{This is the argument: (#1)}

序列

\macro aa

产量:

This is the argument: ()a

假设漂亮打印机将第一个括a在花括号中:

序列

\macro{a}a

产量:

This is the argument: (a)

,略有不同。

相关内容