由于某种原因,这种解决方法有效:
\IfStrEq{#1}{\empty}{\def\tmp{0}}{\ifnum#1>0\def\tmp{1}\else\def\tmp{0}\fi}
\ifnum\tmp=1
TRUE
\else
FALSE
\fi
但这种组合没有
\ifnum\IfStrEq{#1}{\empty}{0}{\ifnum#1>0 1\else 0 \fi}=1%
TRUE
\else
FALSE
\fi
现在我很好奇为什么会这样。
为了完整起见,这里有一个 MVE:
\documentclass{scrbook}
\usepackage[english]{babel}
\usepackage{xstring}
\makeatletter
\newcommand{\TFa}[1]{
\IfStrEq{#1}{\empty}{\def\tmp{0}}{\ifnum#1>0\def\tmp{1}\else\def\tmp{0}\fi}
\ifnum\tmp=1
TRUE
\else
FALSE
\fi
}
\newcommand{\TFb}[1]{
\ifnum\IfStrEq{#1}{\empty}{0}{\ifnum#1>0 1\else 0 \fi}=1%
TRUE
\else
FALSE
\fi
}
% main document
\begin{document}
\TFa{}
\TFa{0}
\TFa{1}
\TFa{-1}
\TFa{99}
\TFb{}
\TFb{0}
\TFb{1}
\TFb{-1}
\TFb{99}
\end{document}
答案1
由于您\ifnum#1>0
似乎假设它#1
是空的或有效的数字(oops
例如不是),因此您的测试比需要的要复杂得多,您可以这样做
\makeatletter % if not in package code
\ifdim#1\p@>\z@
yes
\else
no
\fi
好像#1
为空,测试 1pt > 0pt 是否,如果它是一个数字,那么当该数字为正数时,缩放长度将 > 0pt。
答案2
(对你的评论的回复太长了)其他人已经向你展示了如何让它发挥作用。我会尝试解释为什么你的方法不起作用。
TeX 不像其他语言那样,函数有“返回值”。TeX 是一种宏扩展语言,这基本上就是它所做的。当 TeX 读取您的代码时,它会将处理分为两个主要阶段:扩展和处理。有些情况下(大多数情况下)TeX 会同时执行这两个阶段:如果有需要扩展的内容,它就会扩展;如果有需要处理的内容,它就会处理,然后一切就绪。但是也存在有时称为“仅扩展上下文”的情况,在这种情况下它只会扩展内容而不会执行任何其他操作。其中一种仅扩展上下文是当 TeX 正在扫描数字时,例如,在 an 之后\ifnum
(还有许多其他情况,它们的扩展规则略有不同)。
现在让我们暂停上面的解释,区分扩展的事物和被处理的东西。任何标记(让我们关注控制序列标记,IE,\<something>
)可以是宏或基元。宏是您(或某些包)用 定义的任何东西\def\foo{bar}
,而基元是 TeX 内置的(例如\ifnum
)。宏将始终扩展(在上面的示例中,\foo
扩展为bar
)。基元可以是可扩展的,也可以是不可扩展的(这取决于基元;请参阅此处列出例如\def
, 是不可扩展的,而\ifnum
是。根据经验,如果原语执行赋值,则它不可扩展。其他一切都取决于此。
— 但为什么它不可\IfStrEq
扩展呢?毕竟它是一个宏,所以从上面的定义来看,它必须扩展,对吧?
— 嗯,是的,它确实会扩展,但不是完全扩展。宏是否“安全可扩展”取决于它的实现方式。如果某个宏的实现仅包含可扩展原语或其他(可扩展)宏,则该宏被称为可扩展。否则就不是。
现在让我们回到你的例子和 的仅扩展上下文\ifnum
。当 TeX 看到\ifnum
它开始向前扩展标记时,先查找数字,然后查找<
、=
或>
,然后查找另一个数字(这在 的扩展规则中施加了另一个限制\ifnum
:无论您将什么放在那里都必须扩展为这些标记)。您的工作示例就是这样做的:
\IfStrEq{#1}{\empty}
{\def\tmp{0}}
{\ifnum#1>0 \def\tmp{1}\else\def\tmp{0}\fi}
\ifnum\tmp=1
true
...
这里\IfStrEq
用于普通(而非仅扩展)上下文中,并执行其功能,定义\tmp
扩展(宏,因此会扩展)为0
。1
然后 TeX 看到\ifnum
,它首先扩展\tmp
一次,因此最终像\ifnum1=1
(或\ifnum0=1
,取决于#1
),一切顺利。
但是,第二段代码\IfStrEq
紧接着\ifnum
:
\ifnum\IfStrEq{#1}{\empty}
{0}
{\ifnum#1>0 1\else 0 \fi}=1
true
...
因此 TeX 会扩展\IfStrEq
(一个宏)来寻找数字。经过一次扩展后,它\IfStrEq
变成\xs_ifstar{<code>}{<more code>}
(您可以使用\show\IfStrEq
或看到\texttt{\meaning\IfStrEq}
),因此您得到\ifnum\xs_ifstar<code>...
。\ifnum
继续扩展事物,现在\xs_ifstar
(另一个宏)扩展为\xs_ifnxttok*<more code>...
,然后\xs_ifnxttok
(另一个宏)扩展为\xs_deftok<code code>...
,最终扩展为\let\xs_toksmatch=*\relax
。
所以经过四步扩展后,\ifnum\IfStrEq
变成\ifnum\let\xs_toksmatch=*\relax
,然后\ifnum
看到原语\let
(它执行赋值,因此不可扩展)并停止寻找数字。但是没有找到任何数字,因此 TeX 会抱怨缺少数字并向您显示它看到的内容而不是数字\let
:
! Missing number, treated as zero.
<to be read again>
\let
l.28 \TFb{}
?
这就是为什么\IfStrEq
在仅扩展的上下文中不起作用的原因(IE,它不可扩展)。该命令的不同用法(即不在 之后\ifnum
)将以不同的方式中断,因为扩展规则会有所不同,但它仍然会中断(这里, 例如)。
我希望这个相当冗长的解释能够让您了解扩展的工作原理以及为什么某些命令不能在某些地方使用。
答案3
您可以使用expl3
可扩展的测试。xstring
可扩展测试。和\ifthen
是不是完全可扩展。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand{\testforpositiveargTF}{mmm}
{
\bool_lazy_and:nnTF { !\tl_if_blank_p:e { #1 } } { \int_compare_p:n { #1 > 0 } }
{% not empty and positive
#2
}
{% empty or negative
#3
}
}
\prg_generate_conditional_variant:Nnn \tl_if_blank:n { e } { p, T, F, TF }
\ExplSyntaxOff
\begin{document}
\testforpositiveargTF{}{true}{false} (false)
\testforpositiveargTF{ }{true}{false} (false)
\testforpositiveargTF{\space}{true}{false} (false)
\testforpositiveargTF{\empty}{true}{false} (false)
\testforpositiveargTF{0}{true}{false} (false)
\testforpositiveargTF{-2}{true}{false} (false)
\newcommand{\zero}{0}
\testforpositiveargTF{\zero}{true}{false} (false)
\testforpositiveargTF{1}{true}{false} (true)
\newcommand{\one}{1}
\testforpositiveargTF{\one}{true}{false} (true)
\end{document}