这可能看起来相当愚蠢,但我找不到这个问题的答案。(我已经寻找答案有一段时间了)。
假设我想要一个只有一个参数的宏。当这个参数等于 1 时,我希望宏将单词的单数形式附加到参数中,否则使用复数形式。
我有以下代码:
\newcommand{\sth}[1]{\textbf{(#1
\if1#1thing)\else things)\fi}}
它适用于任何参数除了当它是一个大于 1 但以 1 开头的数字时(例如 11)。
我知道\if
比较两个代币在本例中是字符。我还知道有一些解决方案要么假设#1
始终是数字(例如使用\ifnum)或使用其他软件包(例如如果那么或者pdftex命令)。我不想假设#1
是一个数字,因为看起来清洁工对我来说,我仍然想知道是否存在一个核心 LaTeX 解决方案(无需使用其他软件包)。
编辑:问题是,有没有办法知道参数是否正好是“1”,而无需假设它是一个数字或使用额外的包?
提前致谢
答案1
这是一个\ifnum
可以处理非数字输入的比较。它通过1
与进行比较来实现0#1
。如果#1
是数字,则\ifnum
比较以标准方式进行,因为前导0
不会影响数值。
如果#1
不是数字,则\ifnum
参数扩展在与错误比较之后停止0
(已经打印出#1
),然后打印出things
。
\documentclass{article}
\newcommand{\sth}[1]{\textbf{(#1 \ifnum1=0#1\relax thing\else things\fi)}}
\begin{document}
\sth{1} vs. \sth{2} vs. \sth{11} vs. \sth{no}
\end{document}
答案2
\pdfstrcmp
pdfTeX 扩展了两个标记组并将它们作为字符串进行比较。如果它们相等,则\pdfstrcmp
扩展为0
,可以使用
\ifnum
或进行测试\if
:
\ifnum\pdfstrcmp{#1}{1}=0 % space ends the number zero here
...
\else
...
\fi
或者
\if0\pdfstrcmp{#1}{1}%
...
\else
...
\fi
包pdftexcmds
'\pdf@strcmp
隐藏了不同 TeX 引擎 (pdfTeX、XeTeX、LuaTeX) 的不同名称和方法。不支持“Vanilla”TeX。
如果#1
可以包含易碎的东西,那么 LaTeX 方式是一种受保护的扩展,例如:
\protected@edef\param{#1}%
\def\one{1}%
\ifx\one\param
...
\else
...
\fi
或者如果该论点根本不应该扩展:
\def\param{#1}%
\def\one{1}%
\ifx\param\one
...
\else
...
\fi
答案3
通过使用包含不平衡的 \if.. 或 \or 或 \else 或 \fi 的参数,可以成功地使用 \if..\else..\fi 进行测试。
以下测试无需附加软件包,仅通过扩展即可工作,无需任何 \if 条件。一切都通过分隔的宏参数完成。
当然,您无法成功地将测试宏应用于包含 \outer 标记的参数。
您可以轻松增强测试来分叉“1”或“2”或其他内容/空白。
乌尔里希
%%-------------------------------------------------------------------------
%% Paraphernalia:
%%.........................................................................
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
%%-------------------------------------------------------------------------
%% Check whether argument is empty:
%%.........................................................................
%% \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>}%
\long\def\CheckWhetherNull#1{%
\expandafter\secondoftwo\string{\expandafter\secondoftwo
\expandafter{\expandafter{\string#1}\expandafter\secondoftwo
\string}\expandafter\firstoftwo\expandafter{\expandafter
\firstoftwo\expandafter\secondoftwo\expandafter}\string
}\firstoftwo
}%
%%-------------------------------------------------------------------------
%% Check whether argument contains no exclamation-mark on top-brace-level:
%%.........................................................................
%% \CheckWhetherNoExclamationMark{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that
%% argument which is to be checked does not contain !>}%
%% {<Tokens to be delivered in case that
%% argument which is to be checked does contain !>}%
\long\def\RemoveToExclamationMark#1!{}%
\long\def\CheckWhetherNoExclamationMark#1{%
\expandafter\CheckWhetherNull\expandafter{\RemoveToExclamationMark#1!}%
}%
%%-------------------------------------------------------------------------
%% \ForkDigitOne{<Argument to check>}
%% {<tokens in case argument to check is a
%% single 1-character token of catcode 12>}
%% {<tokens in case argument to check is not a
%% single 1-character token of catcode 12>}
%%.........................................................................
\long\def\AtForkDigitOne#1!!1!#2#3!!!!{#2}%
\long\def\ForkDigitOne#1#2#3{%
\CheckWhetherNoExclamationMark{#1}{%
\AtForkDigitOne
!#1!1!{#3}%<-EMPTY
!!#1!{#2}%
!!1!{#3}%<-ELSE
!!!!%
}{#3}%<-ELSE
}%
\ForkDigitOne{1}{One}{Not One}
\ForkDigitOne{\fi}{One}{Not One}
\ForkDigitOne{111}{One}{Not One}
\ForkDigitOne{!ttt{}111!!}{One}{Not One}
\ForkDigitOne{}{One}{Not One}
\ForkDigitOne{w22e2e}{One}{Not One}
\ForkDigitOne{ }{One}{Not One}
\bye