我想编写一个命令来创建一个向量范数,其语法如下:\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
您不想默认使用\left
and 。真的。您已经被警告了。\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}