考虑以下代码:
我正在尝试编写一个 \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}