根据指定的参数数量忽略传递给命令的参数

根据指定的参数数量忽略传递给命令的参数

考虑以下代码:

我正在尝试编写一个 \newcommand,它将接受 m 或 n 个参数,其中 m < n。这里 m=4,n=6。我想要设置一些东西,这样如果我调用一个 newcommand,并且它传递了 6 个参数,它将忽略后两个参数(如果\fl已定义)。

这样做的原因是我想根据不同的选项合并不同的命令,但我想以相同的方式调用这些命令。

\documentclass{article}

\def\fl{}

\ifdefined\fl
  \newcommand{\xx}[4]
  {#1 #2 #3 #4}
\else
  \newcommand{\xx}[6]{%
    {#1 #2 #3 #4
      \begin{#5}
        \item foo
      \end{#6}
    }
  } \fi

\begin{document}
\xx{a}{b}{c}{d}{enumerate}{enumerate}
\end{document}

说清楚点,我想得到

a b c d

如果\fl已定义,并且

a b c d
\begin{enumerate}
\item foo
\end{enumerate}

如果不是。

答案1

没有什么要求你使用替换文本中的所有参数:

\documentclass{article}

\def\fl{}

\ifdefined\fl
  \newcommand{\xx}[6]
  {#1 #2 #3 #4}
\else
  \newcommand{\xx}[6]{%                                                                                                                                                    
    {#1 #2 #3 #4                                                                                                                                                           
      \begin{#5}                                                                                                                                                           
        \item foo                                                                                                                                                          
      \end{#6}                                                                                                                                                             
    }                                                                                                                                                                      
  } \fi

\begin{document}                                                                                                                              
\xx{a}{b}{c}{d}{enumerate}{enumerate}
\end{document}

\fl定义时输出

在此处输入图片描述

\fl未定义时输出

在此处输入图片描述

为了得到这个,我只需要%在前面放\def\fl{}


\fl如果文档中的状态发生变化,则需要采用更复杂的策略:

\documentclass{article}[12pt]

\makeatletter
\newcommand{\xx}[4]{%
  #1 #2 #3 #4%
  \ifdefined\fl
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\@gobbletwo}%
  {\xx@aux}%
}
\newcommand\xx@aux[2]{%
  \begin{#1}
    \item foo
  \end{#2}
}

\begin{document}
Here \verb+\fl+ is not defined

\xx{a}{b}{c}{d}{enumerate}{enumerate}

\bigskip
\newcommand{\fl}{}

Here \verb+\fl+ is defined

\xx{a}{b}{c}{d}{enumerate}{enumerate}

\end{document}

在此处输入图片描述

答案2

这是一个使用包裹xparse使参数成为#5可选#6的。

如果\fl不是定义,然后我们就可以处理两个都四个参数六个参数版本,如果遇到 5 个参数版本则报告错误。

如果\fl 定义,那么我们将处理 4、5 或 6 个参数的情况,就好像它是 4 个参数版本一样。

在此处输入图片描述

代码:

\documentclass{article}
\usepackage{xparse}

\newcommand{\MyError}[3]{%
    Error: #1: #2 #3%
    %\PackageError{#1}{#2}{#3}% <-- Use this once code is debugged.
}%


\NewDocumentCommand{\xx}{m m m m g g}{%
    \ifdefined\fl
        % only the first four parameters are useful
        \xxFour{#1}{#2}{#3}{#4}%
    \else
        % Allow for 4 or 6 parameters
        \IfNoValueTF{#5}{%
            % #5 not provided, so default back to 4 parameter version
            \xxFour{#1}{#2}{#3}{#4}%
        }{%
            \IfNoValueTF{#6}{%
                % Only 5 parameters were provided
                \MyError{xx}{5 Parameters were provided. Required either 4 or 6 parameters since \textbackslash fl is not defined}{C}%
            }{%
                \xxSix{#1}{#2}{#3}{#4}{#5}{#6}%
            }%
        }%
    \fi
}%

\newcommand{\xxFour}[4]{%
    Four parameters: #1, #2, #3, #4
}%

\newcommand{\xxSix}[6]{%
    \begin{#5}
        \item Parameter 1: #1
        \item Parameter 2: #2
        \item Parameter 3: #3
        \item Parameter 4: #4
        \item Parameter 5: #5
        \item Parameter 6: #6
    \end{#6}
}%

\newcommand{\Test}{% so that we can repeat this 
\textbf{4 paramaters:}
\xx{a}{b}{c}{d}

\bigskip\par
\textbf{5 paramaters:}
\xx{a}{b}{c}{d}{enumerate}

\bigskip\par
\textbf{6 paramaters:}
\xx{a}{b}{c}{d}{enumerate}{enumerate}
}%

\begin{document}
\textbf{\textbackslash fl NOT defined}:

\Test

\bigskip\par
\def\fl{}
\textbf{\textbackslash fl defined}:

\Test

\end{document}

答案3

这里有一些选项(虽然没有在您的设置中经过广泛测试):

选项 A:

定义\xx工作于 4或者6 个参数,通过提前预览来查看是否\bgroup已开始一个新组。

在此处输入图片描述

\documentclass{article}

\makeatletter
\newcommand{\xx@}[2]{%
  #1 #2
}
\newcommand{\xx}[4]{%
  #1 #2 #3 #4
  \@ifnextchar\bgroup\xx@\relax
}
\makeatother

\begin{document}
\xx{a}{b}{c}{d}{enumerate}{enumerate}

\xx{a}{b}{c}{d}

\xx{a}{b}{c}{d}{enumerate}{enumerate}

\end{document}

当然,这没有\fl考虑到。在上面的例子中,\xx@将包含环境定义,有效地指定处理最后两个参数。

选项 B:

按您指定的方式使用它:

\documentclass{article}

\def\fl{}

\ifdefined\fl
  \newcommand{\xx}[4]{%
    #1 #2 #3 #4
  }
\else
  \newcommand{\xx}[6]{%
    #1 #2 #3 #4 #5 #6
  }
\fi

\begin{document}

\xx{a}{b}{c}{d}% or \xx{a}{b}{c}{d}{enumerate}{enumerate}

\end{document}

答案4

  • 以下示例测试fl的定义内部\xx

  • \iffl如果定义了宏,它还会使用更自然的开关而不是测试。

  • 参数的数量减少到 5,因为\begin{#5}\end{#6}不应该有不同的参数。

例子:

\documentclass{article}

\newif\iffl

\newcommand{\xx}[5]{%
  #1 #2 #3 #4%
  \iffl
    \begin{#5}
      \item foo
    \end{#5}%
  \fi
}

\begin{document}
  \flfalse
  \subsection*{Case: flfalse}
  \xx{a}{b}{c}{d}{enumerate}

  \subsection*{Case: fltrue}
  \fltrue
  \xx{a}{b}{c}{d}{enumerate}
\end{document}

结果

相关内容