我尝试了几种方法来测试参数是否为空或等于特定字符。应该如何进行?
顺便问一下,对可以有三个值的参数使用条件代码的最佳方法是什么:空,v,h?
\documentclass{standalone}
\newcommand{\Test}[3]{%
\ifnum #1=1 C'est \'egal à 1 \fi
\if #2v C'est \'egal à v \fi
\ifx #2v C'est \'egal à v \fi
\if #3\empty C'est vide \fi
\ifx #3\empty C'est vide \fi
}
\begin{document}
\Test{1}{v}{}
\end{document}
永远不要说视频......
答案1
如果使用原始的 TeX if 语法,你应该始终注意将测试标记第一的在用户提供令牌之前,否则您无法控制正在测试的内容:
\documentclass{standalone}
\newcommand{\Test}[3]{%
\ifnum #1=1 C'est \'egal à 1 \fi
\if #2v C'est \'egal à v \fi
\ifx #2v C'est \'egal à v \fi
\if #3\empty C'est vide \fi
\ifx #3\empty C'est vide \fi
}
\begin{document}
\Test{2=2}{aa}{!!}
\end{document}
第四个测试永远不会测试是否#3
为空,如果给定一个字符,它会测试它是否为C
。
您应该使用的确切测试取决于您对空的定义。其中哪个是“空”,其中外部{}
是参数的分隔符:{}
{ }
{\empty}
{\mbox{}}
我通常会做类似的事情
\ifx\som@internal@macro#1\som@internal@macro
\som@internal@macro
一些在哪里定义文件中不太可能在参数中使用的宏。然后,如果#1
为空,则测试为
\ifx\som@internal@macro\som@internal@macro
所以测试为真,如果#1
非空(并且不以 开头\som@internal@macro
)则测试为假。
答案2
以下是大卫·卡莱尔的解决方案在一个名为 的宏中\ifempty
。使用它代替 ,\if
如下所示。确保将参数括\ifempty
在花括号中。
\def \ifempty#1{\def\temp{#1} \ifx\temp\empty }
\def \mymacro#1{ \ifempty{#1} empty \else not empty \fi }
\mymacro{something} % prints "not empty"
\mymacro{} % prints "empty"
答案3
如图所示此线程上的 egreg使用\ifstrempty
etoolbox 包中的命令,可以测试给定的字符串是否为空,另外还有一个好处给定字符串中的换行符不会引起问题。
下面是在宏中使用此命令来测试字符串 #1 是否为空的示例:
\usepackage{etoolbox}
\newcommand{\Test}[1]{%
\ifstrempty{#1}%
{%
empty%
}{%
not empty%
}%
}
如果 #1 为空,则此宏还可用于打印 #2;如果 #1 非空,则打印 #3。
\newcommand{\Test}[3]{%
\ifstrempty{#1}%
{%
#2% If #1 is empty
}{%
#3% If #1 is not empty
}%
}
答案4
您说一个参数的值有三种可能。
参数和⟨参数文本⟩宏定义的表示方法,在扩展所讨论的宏时,如何从标记流中收集并处理宏参数。
宏参数反过来是标记的组合。
“价值”一词有点含糊:
您的意思是,恰好有三种不同的标记组合可以收集作为宏观论据?
或者作为 TeX 进行扩展/评估-⟨数字⟩也扮演一个角色吗?
如果两个参数不是由相同的标记组合组成,而是由具有相同数量标记的不同标记组合组成,并且对于所有可能的标记,它们是否也具有相同的“值”钾这钾-th 标记具有相同的
\meaning
,即类似于:\let\One=1 \let\Two=2 argument 1: 1\Two argument 2: \One2
如果它只是关于标记的不同组合,而不同标记的扩展/评估和含义相等不起作用,并且任何可能的组合都不包含花括号或井号等特殊标记(类别代码 1 或 2 或 6 的显式字符标记),则可以通过分隔参数来实现分叉,其中参数分隔符的部分由可能的标记组合形成。没有花括号和井号,因为这些类型的标记不能成为分隔参数分隔符的组成部分。
\documentclass{article}
\makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
{\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%% If e-TeX-extensions are available, you can do:
%\newcommand\UD@CheckWhetherNull[1]{%
% \romannumeral0\if\relax\detokenize{#1}\relax
% \@firstoftwo{\expandafter\expandafter\expandafter}{} \expandafter\@firstoftwo
% \else
% \@firstoftwo{\expandafter\expandafter\expandafter}{} \expandafter\@secondoftwo
% \fi
%}%
%%-----------------------------------------------------------------------------
%% Check whether argument contains ! not nested in braces:
%%.............................................................................
\@ifdefinable\UD@gobbletoExclam{\long\def\UD@gobbletoExclam#1!{}}%
\newcommand\UD@CheckWhetherNoExclam[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletoExclam#1!}%
}%
\newcommand\Test[3]{%
\UD@CheckWhetherNoExclam{#1}{%
\ForkParameterOne!#1!1!{Argument 1 est vide.}%
!!#1!{Argument 1 est \'egal à 1.}%
!!1!{Argument 1 n'est pas vide, n'est pas egal à 1, et est sans ``!''.}%
!!!!%
}{Argument 1 n'est pas vide, n'est pas egal à 1, et est avec ``!''.} %
\UD@CheckWhetherNoExclam{#2}{%
\ForkParameterTwo!#2!v!h!{Argument 2 est vide.}%
!!#2!h!{Argument 2 est \'egal à v.}%
!!v!#2!{Argument 2 est \'egal à h.}%
!!v!h!{Argument 2 n'est pas vide, ni est egal à v, ni est egal à h, et est sans ``!''.}%
!!!!%
}{Argument 2 n'est pas vide, ni est egal à v, ni est egal à h, et est avec ``!''.} %
\UD@CheckWhetherNoExclam{#3}{%
\ForkParameterThree!#3!{Argument 3 est vide.}%
!!{Argument 3 n'est pas vide et est sans ``!''.}%
!!!!%
}{Argument 3 n'est pas vide et est avec ``!''.}%
}%
\@ifdefinable\ForkParameterOne{%
\long\def\ForkParameterOne#1!!1!#2#3!!!!{#2}%
}%
\@ifdefinable\ForkParameterTwo{%
\long\def\ForkParameterTwo#1!!v!h!#2#3!!!!{#2}%
}%
\@ifdefinable\ForkParameterThree{%
\long\def\ForkParameterThree#1!!#2#3!!!!{#2}%
}%
\makeatother
\parindent=0ex
\parskip=\bigskipamount
\begin{document}
\verb|\Test{1}{v}{}| $\to$\\ \Test{1}{v}{}
\verb|\Test{1}{h}{}| $\to$\\ \Test{1}{h}{}
\verb|\Test{}{}{}| $\to$\\ \Test{}{}{}
\verb|\Test{X}{Y}{Z}| $\to$\\ \Test{X}{Y}{Z}
\verb|\Test{!}{!}{!}| $\to$\\ \Test{!}{!}{!}
\verb|\Test{1a}{vb}{}| $\to$\\ \Test{1a}{vb}{}
\end{document}
如果您需要将评估结果作为标记序列(例如,在扩展上下文中),则可以添加一些交换参数和\romannumeral0
扩展:
\documentclass{article}
\makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
{\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%% If e-TeX-extensions are available, you can do:
%\newcommand\UD@CheckWhetherNull[1]{%
% \romannumeral0\ifx\relax\detokenize{#1}\relax
% \@firstoftwo{\expandafter\expandafter\expandafter}{} \expandafter\@firstoftwo
% \else
% \@firstoftwo{\expandafter\expandafter\expandafter}{} \expandafter\@secondoftwo
% \fi
%}%
%%-----------------------------------------------------------------------------
%% Exchanging two arguments:
%%.............................................................................
\newcommand\UD@Exchange[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Check whether argument contains ! not nested in braces:
%%.............................................................................
\@ifdefinable\UD@gobbletoExclam{\long\def\UD@gobbletoExclam#1!{}}%
\newcommand\UD@CheckWhetherNoExclam[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletoExclam#1!}%
}%
%%-----------------------------------------------------------------------------
%% \Test. The result is delivered after two expansion-steps/after two "hits"
%% with \expandafter.
%%.............................................................................
\newcommand\Test[3]{%
\romannumeral0%
\expandafter\UD@Exchange\expandafter{%
\romannumeral0%
\UD@CheckWhetherNoExclam{#3}{%
\ForkParameterThree!#3!{ Argument 3 est vide.}%
!!{ Argument 3 n'est pas vide et est sans ``!''.}%
!!!!%
}{ Argument 3 n'est pas vide et est avec ``!''.} %
}{%
\expandafter\UD@Exchange\expandafter{%
\romannumeral0%
\UD@CheckWhetherNoExclam{#2}{%
\ForkParameterTwo!#2!v!h!{ Argument 2 est vide.}%
!!#2!h!{ Argument 2 est \'egal à v.}%
!!v!#2!{ Argument 2 est \'egal à h.}%
!!v!h!{ Argument 2 n'est pas vide, ni est egal à v, ni est egal à h, et est sans ``!''.}%
!!!!%
}{ Argument 2 n'est pas vide, ni est egal à v, ni est egal à h, et est avec ``!''.} %
}{%
\expandafter\UD@Exchange\expandafter{%
\romannumeral0%
\UD@CheckWhetherNoExclam{#1}{%
\ForkParameterOne!#1!1!{ Argument 1 est vide.}%
!!#1!{ Argument 1 est \'egal à 1.}%
!!1!{ Argument 1 n'est pas vide, n'est pas egal à 1, et est sans ``!''.}%
!!!!%
}{ Argument 1 n'est pas vide, n'est pas egal à 1, et est avec ``!''.} %
}{ }%
}%
}%
}%
\@ifdefinable\ForkParameterOne{%
\long\def\ForkParameterOne#1!!1!#2#3!!!!{#2}%
}%
\@ifdefinable\ForkParameterTwo{%
\long\def\ForkParameterTwo#1!!v!h!#2#3!!!!{#2}%
}%
\@ifdefinable\ForkParameterThree{%
\long\def\ForkParameterThree#1!!#2#3!!!!{#2}%
}%
\makeatother
\parindent=0ex
\parskip=0ex
\topsep=0ex
\partopsep=0ex
\begin{document}
% adjust gap between top-margin and 1st line of text
\hbox{}%
\kern-\headheight
\kern-\headsep
\kern-1in
\kern-\topmargin
\kern-\baselineskip
\kern-\topskip
\kern\ht\strutbox
\kern.5cm
\enlargethispage{.5cm}%
%--------------------------
\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{1}{v}{}%
}
\end{verbatim}
$\to$\\
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{1}{v}{}%
}%
{\tt\frenchspacing\sloppy\string\temp=\meaning\temp\par}%
\kern-\ht\strutbox\kern\dp\strutbox\hrulefill\null
\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{1}{h}{}%
}
\end{verbatim}
$\to$\\
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{1}{h}{}%
}%
{\tt\frenchspacing\sloppy\string\temp=\meaning\temp\par}%
\kern-\ht\strutbox\kern\dp\strutbox\hrulefill\null
\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{}{}{}%
}
\end{verbatim}
$\to$\\
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{}{}{}%
}%
{\tt\frenchspacing\sloppy\string\temp=\meaning\temp\par}%
\kern-\ht\strutbox\kern\dp\strutbox\hrulefill\null
\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{X}{Y}{Z}%
}
\end{verbatim}
$\to$\\
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{X}{Y}{Z}%
}%
{\tt\frenchspacing\sloppy\string\temp=\meaning\temp\par}%
\kern-\ht\strutbox\kern\dp\strutbox\hrulefill\null
\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{!}{!}{!}%
}
\end{verbatim}
$\to$\\
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{!}{!}{!}%
}%
{\tt\frenchspacing\sloppy\string\temp=\meaning\temp\par}%
\kern-\ht\strutbox\kern\dp\strutbox\hrulefill\null
\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{1a}{vb}{}%
}
\end{verbatim}
$\to$\\
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\temp
\expandafter\expandafter\expandafter{%
\Test{1a}{vb}{}%
}%
{\tt\frenchspacing\sloppy\string\temp=\meaning\temp\par}%
\end{document}