\def 中的可选参数

\def 中的可选参数

我想重新定义\sqrt命令(详见好看的 p 次根),到目前为止我有以下内容:

\documentclass{article}

\usepackage{fouriernc} % use the New Century Schoolbook font
\usepackage{amsmath}

\let\oldsqrt\sqrt
\def\sqrt[#1]{\oldsqrt[\leftroot{-3}\uproot{3}#1]}

\begin{document}
This $\sqrt[p]{a}$ looks better than $\oldsqrt[p]{a}$,
since the $p$ does not intersect the root symbol.
\end{document}

但是,当我尝试写入时\sqrt{a},出现错误。如何使#1参数成为可选参数,以便如果未传入该参数,则将根符号上方的区域留空(就像在默认\sqrt命令中一样)?

(这是对大卫的Harish 的回答对上述问题。

答案1

如果您想要最多带有一个可选参数的命令,LaTeX 内置的\newcommand\renewcommand是一种定义它们的简单方法。语法是

\(re)newcommand⟨\name⟩[⟨number of arguments⟩][⟨default value for the first argument⟩]{⟨code⟩]

如果指定第二个可选参数,则第一个参数将\name是可选的。因此,对于你的情况,可以简单地使用

\renewcommand\sqrt[1][]{\oldsqrt[\leftroot{-3}\uproot{3}#1]}

请注意(如您的问题所示),我们不需要指定第二个参数,因为\oldsqrt无论如何都会寻找它,因此该定义在功能上等同于

\renewcommand\sqrt[2][]{\oldsqrt[\leftroot{-3}\uproot{3}#1]{#2}}

如果您需要几个可选参数,或者除第一个参数之外的其他参数应该是可选的,那么您可以链接\@ifnextchars(如 Yiannis 的回答中所述),或使用xparse(如 Peter 的回答中所述)。

答案2

原语\def不理解可选参数。该参数仅在 LaTeX 中提供。您定义的是一个分隔参数:

  \def\sqrt[#1]{...}

这意味着输入必须始终以 [...] 的形式提供,您可以编写任何内容来代替[]。要获得可选参数,您需要使用以下方法在 LaTeX 中定义它:

  \DeclareRobustCommand\sqrt{\@ifnextchar[{true statement}{false statement}}

检查@\ifnextchar是否存在[并相应地分支。您需要在此基础上修改脚本。

命令通常定义为调用两个宏,一个是分隔的,另一个是非分隔的,例如:

  \makeatletter
  \DeclareRobustCommand\sqrt{\@ifnextchar[{\@@sqrt}{\@sqrt}}
  \def\@@sqrt[#1]{I have a square bracket #1}  
  \def\@sqrt#1{I don't have a square bracket #1}
  \sqrt{1}
  \sqrt[3]

现在重新定义amsmath宏就像赤脚走在煤火上,所以需要注意一些事项。首先,为了保存旧命令,我们使用 Oberdiek 的包letltxmacro

   \LetLtxMacro{\oldsqrt}{\sqrt}

其余部分如下所示:

\documentclass{article}
\usepackage{fouriernc} % use the New Century Schoolbook font
\usepackage{amsmath}
\usepackage{letltxmacro}
\makeatletter
\begin{document}
\LetLtxMacro{\oldsqrt}{\sqrt}
\DeclareRobustCommand\sqrt{\@ifnextchar[\@@sqrt\oldsqrt}
\newcommand\@@sqrt[2][]{\oldsqrt[\leftroot{-3}\uproot{3}#1]{#2}}  
\[
   \sqrt{\alpha}\qquad
   \sqrt[\beta]{k} \qquad
   \sqrt[c]{k} \qquad
   \sqrt[d]{k}
\]
\end{document}

在此处输入图片描述

答案3

使用新命令\mysqrt::

这是我在评论中建议的好看的 p 次根使用包裹xparse使前三个参数成为可选参数:

\NewDocumentCommand{\mysqrt}{O{} O{-2} O{2}  m}{\sqrt[\leftroot{#2}\uproot{#3}#1]{#4}}

然后$\mysqrt[p]{a}$就会产生所需的结果:

在此处输入图片描述

请注意,索引中的第一个可选参数\sqrt。以下两个选项是应用于(上述代码中的\leftroot默认为)和(默认为)的调整。-2\uproot2

来自链接问题的示例将被指定为左侧使用默认设置而右侧使用手动调整:

\[\mysqrt[\beta]{k}            \quad\mysqrt[\beta][-3][3]{k}          \]
\[\mysqrt[\beta]{\frac{k}{h}}  \quad\mysqrt[\beta][-2][6]{\frac{k}{h}}\]

得到:

在此处输入图片描述

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\NewDocumentCommand{\mysqrt}{O{} O{-2} O{2}  m}{%
    \sqrt[\leftroot{#2}\uproot{#3}#1]{#4}%
}%

\begin{document}\noindent
This $\mysqrt[p]{a}$ looks better than $\sqrt[p]{a}$,
since the $p$ does not intersect the root symbol.
\end{document}

重新定义现有的\sqrt宏:

如果您希望\sqrt全局重新定义,那么您必须使用包\LetLtxMacro中的选项letltxmacro,因为包中\sqrt已经有可选参数。

参考:

以下产生的结果与上面第二张图相同:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\usepackage{letltxmacro}

\LetLtxMacro{\OldSqrt}{\sqrt}

\RenewDocumentCommand{\sqrt}{O{} O{-2} O{2}  m}{\OldSqrt[\leftroot{#2}\uproot{#3}#1]{#4}}%

\begin{document}\noindent
\[\sqrt[\beta]{k}            \quad\sqrt[\beta][-3][3]{k}          \]
\[\sqrt[\beta]{\frac{k}{h}}  \quad\sqrt[\beta][-2][6]{\frac{k}{h}}\]
\end{document}

答案4

这个答案是关于解决具体的问题,即将\leftroot和初始化\uproot为不同于默认值的值,保留在特定情况下使用它们的可能性。

诀窍是注意amsmath使用作为参数给出的值\leftroot\uproot设置两个计数寄存器,\leftroot@\uproot@初始化为零。这发生在内部宏中,称为\root。因此可以这样做

\usepackage{etoolbox}
\makeatletter
\patchcmd{\root}{\uproot@\z@}{\uproot@3 }{}{}
\patchcmd{\root}{\leftroot@\z@}{\leftroot@-3 }{}{}
\makeatother

现在将应用这些初始值,但是说

\sqrt[\leftroot{1}x]{y}

会产生与未打补丁时相同的结果\sqrt[\leftroot{1}\uproot{3}x]{y},这在特定情况下可能会有用。同样,\sqrt[\leftroot{0}\uproot{0}x]{y}会产生与原始 相同的结果\sqrt[x]{y}

正如 Stefan Lehmke 在他的评论中指出的那样,改变 的含义\sqrt并不真正值得推荐。但是,为\leftroot和设定不同的默认值对于某些文档字体来说是合理的。重要的是要知道新的相对于和 的行为\uproot方式。\sqrt\leftroot\uproot

制作\leftroot\uproot添加默认值需要进行非常广泛的修补\root

\makeatletter
\def\default@leftroot{-3} % set the default value of leftroot
\def\default@uproot{3}    % set the default value of uproot
\renewcommand{\root}{\relaxnext@
  \DN@{\ifx\@let@token\uproot\let\next@\nextii@\else
   \ifx\@let@token\leftroot\let\next@\nextiii@\else
   \let\next@\plainroot@\fi\fi\next@}%
  \def\nextii@\uproot##1{\uproot@\numexpr(\default@uproot+##1)\relax\FN@\nextiv@}%
  \def\nextiv@{\ifx\@let@token\@sptoken\DN@. {\FN@\nextv@}\else
   \DN@.{\FN@\nextv@}\fi\next@.}%
  \def\nextv@{\ifx\@let@token\leftroot\let\next@\nextvi@\else
   \let\next@\plainroot@\fi\next@}%
  \def\nextvi@\leftroot##1{\leftroot@\numexpr(\default@leftroot+##1)\relax\plainroot@}%
   \def\nextiii@\leftroot##1{\leftroot@\numexpr(\default@leftroot+##1)\relax\FN@\nextvii@}%
  \def\nextvii@{\ifx\@let@token\@sptoken
   \DN@. {\FN@\nextviii@}\else
   \DN@.{\FN@\nextviii@}\fi\next@.}%
  \def\nextviii@{\ifx\@let@token\uproot\let\next@\nextix@\else
   \let\next@\plainroot@\fi\next@}%
  \def\nextix@\uproot##1{\uproot@\numexpr(\default@uproot+##1)\relax\plainroot@}%
  \bgroup\uproot@\default@uproot \leftroot@\default@leftroot\relax \FN@\next@}
\makeatother

(感谢 Stefan Lehmke 发现初始版本中的错误。)

相关内容