有条件地忽略其中一个参数的宏

有条件地忽略其中一个参数的宏

假设我想编写嵌套方程,其中包含相当多的嵌套括号/分隔符,例如()[]{}||,也许还有其他。还假设我认为如果外部分隔符比内部分隔符稍大(如果可能),这些内容看起来会更好,看起来像是“框住”了它们。

我可以写如下内容:

$\pi_G\big(f\big(\big[[v]_{\sim}\big]_{\sim''}\big)\big)$

但这些\big(...\big)东西有点丑陋,妨碍了从 LaTeX 代码中看到发生了什么。如果我可以写得更好:

$\pi_G\mybig(){f\mybig(){\mybig[]{[v]_{\sim}}_{\sim''}}}$

这里的()after\mybig表示宏参数应该被 包围\big(...\big)。如果是[],那么参数应该被 包围\big[...\big],依此类推。

但等等!这实际上是可以做到的;只需要定义带有三个参数的宏,如下所示:

\newcommand{\mybig}[3]{\big{#1}#3\big{#2}}

真好。但不幸的是,当我想使用括号时,这种方法不太好用,比如

$\mybig{}{(x)}$

这里,{}实际上是一个组,并且只构成一个参数。所以这失败了。当然,以下两种方法都有效,但意味着宏的使用在外观上不太统一(这不太令人愉快):

$\mybig{}{}{(x)}$
$\mybig\{\}{(x)}$

所以我真正需要的是测试参数 #1 是否为空(表示宏调用后紧接着一个空组,即{})。如果是,则宏“跳”到第三个参数,并输入\big\{#3\big\}。有办法做到这一点吗?

答案1

这是另一个 LaTeX3 版本。

\documentclass{article}
%\url{http://tex.stackexchange.com/q/131136/86}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new_nopar:Npn \paren_set:nnnn #1#2#3#4
{
  \use:c {#1} #2 #4 \use:c {#1} #3
}

\cs_new_nopar:Npn \paren_get_first:nn #1#2
{
  \tl_if_empty:nTF {#1}
  {
    \paren_set:nnnn {big} {\lbrace} {\rbrace} {#2}
  }
  {
    \tl_if_single:nTF {#1}
    {
      \paren_set:nnnn {big} {#1} {#2}
    }
    {
      \tl_if_empty:nTF {#2}
      {
        \paren_set:nnnn {#1} {\lbrace} {\rbrace}
      }
      {
        \paren_set:nnnn {#1} {#2}
      }
    }
  }
}

\DeclareDocumentCommand \MyBig { }
{
  \paren_get_first:nn
}

\ExplSyntaxOff

\begin{document}

\[
\MyBig(){\frac12} \quad
\MyBig[]{\frac12} \quad
\MyBig{}{\frac12} \quad
\MyBig(.{\frac12} \quad
\MyBig\{.{\frac12} \quad
\MyBig{Big}(){\frac12} \quad
\MyBig{bigg}[]{\frac12} \quad
\MyBig{Bigg}{}{\frac12} \quad
\MyBig(.{\frac12} \quad
\MyBig\{.{\frac12}
\]

\end{document}

这使用以下逻辑:

排版命令接受四个参数:大小、左分隔符、右分隔符和内容。调度程序必须根据输入确定这些参数应该是什么。选项如下:

  1. \MyBig{}{Content}. 用于big大小\lbrace,,\rbrace用于分隔符。
  2. \MyBig(){Content}. 用于big大小(,,)用于分隔符。
  3. \MyBig{bigg}{}{Content}. 用于bigg大小\lbrace,,\rbrace用于分隔符。
  4. \MyBig{bigg}(){Content}. 用于bigg大小(,,)用于分隔符。

因此,调度程序执行以下操作:

  1. 读入两个参数。这是安全的,因为总是至少有两个。
  2. 检查第一个。它是空的吗?如果是,则命令一定是,\MyBig{}{Content}所以我们将其输入为\big\{<Content>\big\}。到此结束。
  3. 如果第一个不为空,我们测试它是否是单例。如果是,参数一定是分隔符。第二个将是结束分隔符,我们还没有获取内容。所以我们用 调用排版器,{big}{#1}{#2}它将从流中获取内容。
  4. 如果第一个不是单例,则它是一个大小参数。因此第二个是分隔符,所以我们对其进行测试。如果它为空,我们的分隔符是括号,因此我们用 调用排版程序{#1}{\lbrace}{\rbrace},下一组是内容。
  5. 现在的情况是,第一个不是单例,第二个不是空的。所以第二个是分隔符,我们必须从流中获取结束分隔符和内容,所以我们调用 typesetter{#1}{#2}并让它从流中获取其余内容。

分隔符

请注意,分隔符不必匹配,但如果您想要不匹配的括号,则必须使用\{\}(或\lbrace\rbrace)。

答案2

使用 LaTeX3,xparse以及一些技巧(已解释),效果是完全可以实现的。

\MyBig 我们设置了一个名为(为了符合当前惯例,这里大写)的文档级接口宏。此宏可以采用三个参数:

  • <>一个可选参数,以,分隔
  • 一个“正常”的“可选参数”,用于测试是否需要[]分隔符,以及
  • 一个强制性参数,用于检查我们是否传递了一个空参数,表示需要{}分隔符。

因此,文档级宏的唯一目的是分派给其他函数,进一步扫描输入流以查找所需的标记 - 分派器决定哪个宏获取输入流,宏决定它需要多少个标记。(我不相信有任何方法可以严格地拥有一个要求更多标记的开关,如果有,那肯定不漂亮。)

输出

\documentclass{article}
\usepackage{expl3,xparse}

\ExplSyntaxOn

\msg_new:nnnn { mybig } { invalid-argument }
{ Argument~ `#1`~ invalid. }
{ The~ apparent~ optional~ argument~ should~ never~ take~ a~ value;~
  it~ is~ solely~ for~ the~ purpose~ of~ delimiter~ specification.}

% Typeset, in braces of size #1, the content in #2
\cs_new:Npn \MyBig_braces #1 #2
 {
  #1\{ #2 #1\}
 }

% Typeset, in brackets of size #1, the content in #2
\cs_new:Npn \MyBig_brackets #1 #2
 {
  #1[ #2 #1]
 }

% Typeset, in delimiters #2 and #3 of size #1, the content in #4
\cs_new:Npn \MyBig_other #1 #2 #3 #4
 {
  #1#2 #4 #1#3
 }

 % If the (second) optional argument is empty, we were passed the
 % delimiters [], so dispatch.  If the optional argument is not empty
 % and has a value, then something went horribly wrong.  Otherwise
 % (NoValue), check to see if the mandatory argument is empty.  If it
 % is, we want the {} delimiter, so dispatch.  Otherwise, dispatch the
 % generic handler.
\NewDocumentCommand \MyBig { D<>{\Big} o m }
 {
  \str_if_eq_x:nnTF { #2 } { }
   { \MyBig_brackets { #1 } { #3 } }
   {
    \IfValueTF { #2 }
     { \msg_error:nnn { mybig } { invalid-argument } { #2 } }
     {
      \str_if_eq_x:nnTF { #3 } { }
        { \MyBig_braces { #1 } }
        { \MyBig_other { #1 } { #3 } }
     }
   }
 }
\ExplSyntaxOff

\begin{document}

\[
\MyBig(){\frac12} \quad
\MyBig[]{\frac12} \quad
\MyBig{}{\frac12} \quad
\MyBig<\big>{}{\frac12} \quad
\MyBig<\Bigg>[]{\MyBig{}{\int_0^\infty}}
\]

% \[ \MyBig<\Bigg>[bad]{\MyBig{}{\int_0^\infty}} \]

\end{document}

答案3

您可以通过测试是否存在带星号形式的命令来执行此类操作,在这种情况下会使用\{和。\}

\makeatletter
\def\mybig{\@ifstar{\@mybig}{\@@mybig}}
\def\@mybig#1{\left\{#1\right\}}
\def\@@mybig#1#2#3{\left#1#3\right#2}
\makeatother

然后是以下代码

\[\mybig[]{abc}\]

\[\mybig*{\mybig{\langle}{\rangle}{abc}}\]

\[\mybig.{|}{\int_a^b 2x\mathrm{d}x = x^2}_{a}^{b}\]

会产生类似

在此处输入图片描述

更新

下面是一些测试空参数的代码。

\documentclass{article}

\makeatletter
\def\mybig#1{%%"
  \def\@my@temp{#1}%%
  \ifx\@my@temp\@empty\expandafter\@mybig\else
                      \expandafter\@@mybig\expandafter\@my@temp\fi}
\def\@mybig#1{\left\{#1\right\}}
\def\@@mybig#1#2#3{\left#1#3\right#2}
\makeatother

\begin{document}

\[\mybig[]{abc}\]

\[\mybig{}{\mybig{\langle}{\rangle}{abc}}\]

\[\mybig[]{ \int_a^b 2x\mathrm{d}x }^2\]

\end{document}

在此处输入图片描述

但这种事情并不是万无一失的!

答案4

您可以使用一个简单的条件来做到这一点,测试第一个参数是否为空(另一件事是这是否会产生良好的印刷效果;例如,在下面的第二个代码中,实际上不需要增加大小分隔符):

\documentclass{article}
\usepackage{amsmath}

\newcommand\mybig[3]{%
\if\detokenize{#1}\relax\relax
  \bigl\{#3\bigr\}
\else
  \bigl#1#3\bigr#2
\fi}

\begin{document}

$\mybig{\lvert}{\rvert}{\lvert x-y\rvert}$

$\mybig{}{}{\lvert x-y\rvert}$

\end{document}

在此处输入图片描述

相关内容