如何使用 Futurelet 扫描来重新定义现有命令的参数数量和类型?

如何使用 Futurelet 扫描来重新定义现有命令的参数数量和类型?

我想知道如何使用 Futurelet 通过自己的命令重新定义现有命令来确定参数的数量和类型?基本上我想做的类似于

\renewcommand{\log}[2][]{\mathrm{log}_{#1}\left( #2 \right)}

但是有一个附加选项,即用户可以使用不带参数的命令,即写入\log 5以获得输出日志 5,因为有些人更喜欢写不带括号的对数。

这是我尝试过的

%logarithm
\newcommand{\logRM}{\mathrm{log}}                           %log operator
\newcommand{\logOneArg}[1]{\logRM\left(#1\right)}           %\logRM()
\newcommand{\logTwoArgs}[2][]{\logRM_{#1}\left(#2\right)}   %\logRM_basis()
\DeclareRobustCommand\log{\futurelet\logNext\logCheck}

\def\logCheck{%
  \ifx\bgroup\logNext \expandafter\logOneArg                %if \log is followed by {
  \else%
  \ifx[\logNext \expandafter\logTwoArgs                     %if \log is followed by [
  \else%
  \expandafter\logRM                                        %otherwise
  \fi%
  \fi%
}

我遇到了两个问题。其中一个是可选参数没有像我想象的那样工作,而是\log[2]{8}输出了 log()[2]8。另一个问题是我收到一条错误消息,因为\log已经定义了。我试图通过将上面的命令表示为来规避这个问题,\xlog然后尝试以下方法之一,但都没有奏效。

\def\log{\xlog}
\let\log\xlog
\renewcommand{\log}{\xlog}

\edit:
在一个问题中提出两个问题可能不太明智。因此,以下是我想要的无参数情况的信息。如果我们省略可选参数,那么

%logarithm
\newcommand{\logRM}{\mathrm{log}}                           %log operator
\newcommand{\logOneArg}[1]{\logRM\left(#1\right)}           %\logRM()
\DeclareRobustCommand\xlog{\futurelet\logNext\logCheck}

\def\logCheck{%
  \ifx\bgroup\logNext \expandafter\logOneArg                %if \log is followed by {
  \else%
  \expandafter\logRM                                        %otherwise
  \fi%
}

定义一个如果我没有任何参数就不会有括号的命令,即我可以写出\xlog^+(x)对数的正部分,并\xlog{\frac{x+1}{x}}在更复杂的表达式周围使用不同大小的括号。

现在的一个问题是,即使 \log 已经定义,我如何调用此函数 \log?另一个问题是如何扩展此宏以允许额外的可选参数,例如对数的基数,因为它似乎不像我在第一篇文章中发布的那样工作。


我希望它能发挥作用,这一点已在我上面编辑的帖子中列出。它与 Futurelet 配合使用,以查看是否有任何参数,如果我们像我编辑的问题中那样省略带有可选参数的情况,那么

\xlog^+ : [1, \infty) \to \mathbb{R}_+
\xlog{\frac{x}{x+1}}

两者都产生了我们期望的输出(分别是log^+ : [1, \infty) \to Rlog(x/(x+1)))。我想我要说的是,我希望以这样一种方式编写此函数,即如果我不写括号,LaTeX 就不会等待参数,因为不会有括号。抱歉,我弄错了括号,我不是母语人士,但至少我现在知道了。

\edit:
考虑了你关于间距的评论,并意识到概括命令的更好方法\log当然是使用\let,因此我们保留旧命令的所有功能并获取新命令,即使用类似这样的命令

\let\logRM\log                                                  %log operator
\newcommand{\logOneArg}[1]{\logRM\left(#1\right)}               %\logRM()
%\newcommand{\logTwoArgs}[2][]{\logRM_{#1}\left(#2\right)}      %\logRM_basis()
\DeclareRobustCommand\xlog{\futurelet\logNext\logCheck}         %look what next character is
\def\logCheck{%
  \ifx\bgroup\logNext \expandafter\logOneArg%                   %if \log is followed by {
  \else%
  %\ifx[\logNext \expandafter\logTwoArgs%                       %if \log is followed by [
  %\else%
  \expandafter\logRM                                            %otherwise
  %\fi%
  \fi%
}
\renewcommand{\log}{\xlog}

现在,如果\log后面没有任何括号,它的行为与初始的 一样\log,因此如果我们想在 nath 中使用括号,我们仍然可以这样做。另一方面,如果我们写,\log{expression}我们会得到括号中的表达式。现在唯一剩下的问题是如何扩展它以采用可选参数,例如对数的底数。

答案1

首先收集可选参数;然后检查^并最后检查{

\documentclass{article}
\makeatletter
\let\@@log\log
\renewcommand{\log}[1][]{%
  \@@log_{#1}\@ifnextchar^\log@withexp\log@maybeparen}
\def\log@withexp^#1{^{#1}\log@maybeparen}
\def\log@maybeparen{\@ifnextchar\bgroup{\log@paren}{}}
\def\log@paren#1{\mathopen{}\left(#1\right)\mathclose{}}

\makeatother

\begin{document}
$\log 2+\log[2]2$

$\log{2}+\log[2]{2}$

$\log^{+}2+\log[2]^{+}2$

$\log^{+}{2}+\log[2]^{+}{2}$
\end{document}

在此处输入图片描述

作为练习,这里有一个解析版本:

\usepackage{xparse}
\makeatletter
\let\@@log\log
\DeclareDocumentCommand{\log}{o t^}{
  \@@log
  \IfNoValueTF{#1}{}{_{#1}}
  \IfBooleanTF{#2}{\log@exp}{\log@afterexp}
}
\DeclareDocumentCommand{\log@exp}{m}{^{#1}\log@afterexp}
\DeclareDocumentCommand{\log@afterexp}{g}{
  \IfNoValueTF{#1}{}{\mathopen{}\left(#1\right)\mathclose{}}
}
\makeatother

答案2

编辑:我的第一个回答误解了这个问题)

定义这种通用智能宏的基本问题是,它们必须预测您想要处理的各种情况。实际上,您必须让宏在幕后切换您能想到的所有用法。我不清楚这是否值得付出努力;例如,您希望(在评论中)能够编写\log^+{x}并正确解析它,但您想要写\log_2{x},而是提供下标作为可选参数::\log[2]{x}再多一个字符,而且是一个尴尬的字符(无论如何,在我的键盘上)。

我可以看到其他问题。例如,您希望它注意到输入中没有给出括号或圆括号,并在输出中省略它们,因此\log 20变成了log 20而不是log(20),正如 Peter Grill 向我指出的那样。那 呢\log 100000?对于大数字,我有时喜欢使用siunitx来插入逗号:\log \num{100000}。您的宏必须处理这一点。还有手写的数字符号,如\log 1e6。您也很难识别符号\log \colon \mathbb{R}^+ \to \mathbb{R},除非您制作\log{}一个特殊情况不是在空参数周围打印括号。

甚至将参数放在调整大小的括号中的基本目标也不是那么简单。如果你写 会怎么样\log((x + 1)(x + 2))?有一种可接受的观点认为,外面的括号应该比里面的括号大,以便在视觉上区分公式的各个部分。使用\left和无法做到这一点\right。如果你写 ,\log(\sum_{n = 1}^\infty ...)你会得到巨大的括号。这个nath包(我认为)处理得更优雅。

我的观点是,当你只想做以下事情时,最好不要让计算机读懂你的想法:log像数学运算符一样打印单词(\DeclareMathOperator如果\log尚未定义,我们可以使用这种方法。你还记得在自己的宏中注意空格吗?);如果代码中有基数,则放入基数(使用下标很容易做到,下标与可选参数一样是可选的);将实际参数放在调整大小的括号中,我认为这实际上是不是你想要什么。

最后,回答您修改后的帖子中提出的问题:

回答:使用\renewcommand{\log}{\xlog}

相关内容