比较传递给宏的参数

比较传递给宏的参数

我想编写一个命令来创建一个向量范数,其语法如下:\xnorm{v}

我希望标准分隔符能够适应 中包含的表达式的大小\xnorm{},但我还想要一个可选参数,允许手动设置分隔符大小。概念如下:

\newcommand{\xnorm}[2][adapt]{\LeftDelim{#1}\|\, #2\, \RightDelim{#1}\|}

如果用户没有给出第一个参数,则扩展为;如果用户给出了第一个参数,则扩展为\LeftDelim。命令类似。\left\Big\Big\RightDelim

但这只是一个想法,实际操作起来会遇到很多问题,我的尝试如下:

\newcommand{\StringA}{adapt}
\newcommand{\StringB}{aaaaa} % This is temporary definition only, because this command is required to be well-defined.
\newcommand{\LeftDelim}[1]
{
\renewcommand{\StringB}{#1}
\ifx\StringA\StringB
\left
\else
#1
\fi
}
\newcommand{\RightDelim}[1]
{
\renewcommand{\StringB}{#1}
\ifx\StringA\StringB
\right
\else
#1
\fi
}
\newcommand{\xnorm}[2][adapt]{\LeftDelim\noexpand#1\|\, #2\, \RightDelim\noexpand#1\|}

有了上述内容,我的使用方式\xnorm如下:

\begin{document}
\begin{dislpmaymath}
\xnorm[\Big]{X} \xnorm{\int_0^T}
\end{displaymath}
\end{document}

问题:

上面的第一次使用\xnorm是正确的,但第二次使用会产生与 等价的结果adapt\|\int_0^T adapt\|。看来我的宏中的\StringA和 的比较\StringB失败了。另一方面,代码

\begin{displaymath}
\LeftDelim{adapt}\| {\int_0^T} \RightDelim{adapt}\|
\end{displaymath}

\LeftDelim生成预期结果 - 具有大范数分隔符的积分符号。因此,问题可能在于扩展和的参数。但我不知道应该改变什么。我已经对和命令\Rightdelim进行了大量操作,但没有得到积极的结果。\expand\expandafter

答案1

您不想默认使用\leftand 。真的。您已经被警告了。\right

现在,你能做的最好的事情就是使用mathtools并输入

\usepackage{mathtools}
\DeclarePairedDelimiter{\xnorm}{\lvert}{\rvert}

这样你就可以使用

$\xnorm{v}$       % not expanding version
$\xnorm[\big]{v}  % slightly bigger
$\xnorm[\Big]{v}  % bigger
$\xnorm[\bigg]{v} % even bigger
$\xnorm[\Bigg]{v} % quite enormous
$\xnorm*{v}$      % self-adapting (with \left and \right)

如果你想自己实现它,并且以错误的方式,即使用自动\left\right(我说过这是一个糟糕的选择吗?嗯,是的),以下是方法

\makeatletter
\newcommand{\xnorm}[2][]{%
   \if\relax\detokenize{#1}\relax
     \expandafter\@firstoftwo
   \else
     \expandafter\@secondoftwo
   \fi
   {\left|#2\right|}%
   {\mathopen{#1|}#2\mathclose{#1|}}%
}
\makeatother

并像以前一样调用,不同之处在于您不再有*版本。

更好的选择是使用xparse,它还允许指定一个空的可选参数(使用上面的宏将导致使用\left\right):

\usepackage{xparse}
\NewDocumentCommand{\xnorm}{om}{%
  \IfNoValueTF{#1}
    {\left|#2\right|}
    {\mathopen{#1|}#2\mathclose{#1|}}%
}

但请帮自己一个忙,只在真正需要时才使用和添加。我已经说过了吗\DeclarePairedDelimiter\left\right

答案2

请始终发布完整的文档,而不是必须组装的片段,这样您就可以测试您的示例并避免\begin{dislpmaymath}

最初的错误是你从来没有传递#1给你的左宏和右宏,你总是传递单个标记\noexpand

那么如果你没有使用\left而使用了#1( \big),你传递的\fi参数不是分隔符,而是 ,\big那么事情就会变得非常错误。你需要\expandafter并且你需要否则%,后面的标记#就是空格标记,而不是\fi

请注意,这可以修复错误,但仍在左侧和右侧使用,如果在左侧和右侧\Big使用,您将获得更好的间距。\Bigl\Bigr

\documentclass{article}

\begin{document}


\newcommand{\StringA}{adapt}
\newcommand{\StringB}{aaaaa} % This is temporary definition only, because this command is required to be well-defined.
\newcommand{\LeftDelim}[1]
{
\renewcommand{\StringB}{#1}
\ifx\StringA\StringB
\left
\else
\expandafter#1%
\fi
}
\newcommand{\RightDelim}[1]
{%
\renewcommand{\StringB}{#1}%
\ifx\StringA\StringB
\right
\else
\expandafter#1%
\fi
}
\newcommand{\xnorm}[2][adapt]{\LeftDelim{#1}\|\, #2\, \RightDelim{#1}\|}


\begin{displaymath}
\xnorm[\Big]{X} \xnorm{\int_0^T}
\end{displaymath}
\end{document}

相关内容