为 \Big、\bigg 等定义宏

为 \Big、\bigg 等定义宏

是否可以让宏的行为就像直接编写的一样?

\documentclass{article}
\usepackage{amsmath}

\newcommand{\veca}{|_{\vec{a}}}

\begin{document}

\[
\frac{f(\vec{x})}{g(\vec{x})}\bigg\veca \qquad \frac{f(\vec{x})}{g(\vec{x})}\bigg|_{\vec{a}}
\]

\end{document}

在此处输入图片描述

答案1

和朋友的默认定义\Big将分隔符设置为左分隔符,因此在其上添加下标最终会成为分隔列表中的第一个元素,因此不会相对于分隔符放置。可以通过以\Big相反的方式定义和朋友来避免这种情况:将分隔符设为右分隔符,这样下标就成为整个分隔列表的下标。

虽然这可以修复位置,但它会对下标的放置方式产生副作用(大多数\nulldelimiterskip为零,样式始终为脚本样式),但对于大多数用例来说,这并不重要。

鉴于amsmath定义\big基于\bBigg@它足以改变该宏的定义:

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\renewcommand \bBigg@[2]{%
  {\@mathmeasure\z@{\nulldelimiterspace\z@}%
     {\left.\vcenter to#1\big@size{}\right#2}%
   \box\z@}}
\makeatother

\newcommand{\veca}{|_{\vec{a}}}

\begin{document}

\[
\frac{f(\vec{x})}{g(\vec{x})}\bigg\veca \qquad \frac{f(\vec{x})}{g(\vec{x})}\bigg|_{\vec{a}}
\]

\end{document}

在此处输入图片描述

答案2

这是@DavidCarlisle 建议采用veca可选参数的实现,不同之处在于我建议将其设置\biggr为可选参数的默认值。

在此处输入图片描述

\documentclass{article}
\usepackage{amssymb}
\providecommand{\veca}[1][\biggr]{#1\vert_{\vec{a}}}

\begin{document}
\[
\frac{f(\vec{x})}{g(\vec{x})}\veca
\quad
\frac{u(\vec{x})}{v(\vec{x})}\veca[\Bigr]
\quad
h(\vec{z})\veca[]
\]
\end{document}

答案3

这更多的是一种评论而不是答案,但是这种构造在 ConTeXt LMTX(即使用 luametatex 引擎)中可以开箱即用。

\define\veca{\rvert_{\vec{a}}}

\starttext
\startformula
\frac{f(\vec{x})}{g(\vec{x})}\Bigg\veca \qquad \frac{f(\vec{x})}{g(\vec{x})}\Bigg|_{\vec{a}}
\stopformula

\stoptext

这使

在此处输入图片描述

我不确定内部有什么不同才能使其正常工作。

\bigg请注意和的大小\Bigg不同,因为 ConTeXt 对分隔符的缩放略有不同,并且下标的位置也不同(这是因为 luatex 引擎从字体中读取间距值;在 lualatex 中也会获得类似的间距)。

答案4

在此处输入图片描述

\documentclass{article}
\usepackage{amsmath}
\usepackage{expl3}

\makeatletter
\ExplSyntaxOn

\cs_set_eq:NN \better_big:nn \bBigg@

\cs_set:Npn \bBigg@ #1#2 {
  \tl_set:Nx \arg_rest_tokens { \tl_tail:N {#2} }
  \tl_set:Nx \arg_first_token { \tl_head:N {#2} }
  \tl_set:Nx \arg_first_token_exp { \tl_head:f {#2} }
  \exp_last_unbraced:No \token_if_eq_meaning:NNT \arg_first_token \delimiter {
    \use_none_delimit_by_q_nil:w
  }
  \exp_last_unbraced:No \token_if_eq_meaning:NNF \arg_first_token_exp \delimiter {
    \exp_last_unbraced:Nno \str_if_in:nnF {\{\}} {\arg_first_token} {
      \int_compare:nF { \exp_last_unbraced:NNV \delcode`\arg_first_token > 0 } {
        \use_none_delimit_by_q_nil:w
      }
    }
  }
  \better_big:nn {#1} {\arg_first_token} \arg_rest_tokens
  \use_none_delimit_by_q_stop:w
  \use_none_delimit_by_q_nil:w \q_nil
  \better_big:nn {#1}{#2}
  \use_none_delimit_by_q_stop:w \q_stop
}

\ExplSyntaxOff
\makeatother

\newcommand{\veca}{|_{\vec{a}}}
\newcommand{\ketb}{\rangle^*}
\newcommand{\lnorm}{\|}
\newcommand{\rnorm}{\|_\infty}


\begin{document}

Custom macros next to \verb|\Big, \bigg|, etc
\[
\frac{f(\vec{x})}{g(\vec{x})}\bigg\veca \qquad
\big\lnorm A\vec{x} \big\rnorm \qquad
\Big|\Phi(t)\Big\ketb
\]

Doesn't break the regular behaviour
\[
\frac{f(\vec{x})}{g(\vec{x})}\bigg|_{\vec{a}} \qquad
\big\| A\vec{x} \big\|_\infty \qquad
\Big|\Phi(t)\Big\rangle^*
\]

\end{document}

这个问题本身看起来相当简单,不是吗?然而,说实话,它似乎比我最初想象的要难得多。

我花了很多功夫才终于解决了这个问题。我必须感谢所有为此做出贡献并帮助我解决相关问题的人。

特别感谢埃格尔想出了办法检测分隔符一般来说。


解释

所有\big\bigg\Big\Bigg均定义于amsmath就像这样

\renewcommand{\big}{\bBigg@\@ne}
\renewcommand{\Big}{\bBigg@{1.5}}
\renewcommand{\bigg}{\bBigg@\tw@}
\renewcommand{\Bigg}{\bBigg@{2.5}}
\ifx\leavevmode@ifvmode\@undefined
\def\bBigg@#1#2{%
  {\@mathmeasure\z@{\nulldelimiterspace\z@}%
     {\left#2\vcenter to#1\big@size{}\right.}%
   \box\z@}}
\else
\def\bBigg@#1#2{\leavevmode@ifvmode
  {\@mathmeasure\z@{\nulldelimiterspace\z@}%
     {\left#2\vcenter to#1\big@size{}\right.}%
   \box\z@}}
\fi

因此更改仅需应用于\bBigg@

首先想到的就是简单地扩展\bigs 命令的参数。乍一看这可行,但实际上它破坏了一些情况,例如\big\vert会导致错误。

因此,最终实现的想法如下:检查参数是否可扩展,如果是,则检查扩展的第一个参数,即\veca的扩展{|_\vec{a}},然后我检查该列表的第一个标记,如果它是分隔符,那么我仅将其传递给命令\big,其他所有内容都只是向右附加。

相关内容