eTeX 中的构造\numexpr...\relax
允许评估数值表达式,并且它会在进行过程中完全扩展标记。
pdfTeX 中的构造\pdfstrcmp{...}{...}
让我们可以在完全扩展并转换为字符串(使用\detokenize
)之后比较两个标记列表。
是否存在特定的标记列表(无参数宏)\foo
,可以\the\numexpr\foo\relax
正确生成整数,但\pdfstrcmp{\foo}{}
会导致 TeX 错误? 似乎两种情况下的扩展行为相同,但一种将其参数转换为整数,另一种将其参数转换为字符串。
答案1
我看到两种情况,其中\the\numexpr...\relax
有效,但\pdfstrcmp{}{...}
会爆炸,不包括明显的...
被替换的情况0\relax\undefined
,过早终止\numexpr
。
TeX 将其解释
`\a
为数字,而不扩展\a
。因此,\the\numexpr`\a\relax
扩展为97
( 的字符代码a
),而如果未定义,\pdfstrcmp{}{`\a}
则会爆炸。\a
使用
\protected
控制序列也会引起麻烦,因为它们在 中被强制“从左边”扩展\numexpr
,但不会被 扩展\pdfstrcmp
。例如\protected\def\gob#1{} \the\numexpr 0\gob\undefined \relax \pdfstrcmp{}{0\gob\undefined}
在 的情况下\numexpr
,\gob
被扩展并删除\undefined
控制序列。然而,在第二种情况下,\edef
类似扩展不会改变\protected
控制序列\gob
,而是继续扩展\undefined
,而 是未定义的。
我最初的目标是定义一个宏,它接受一个可以为空或整数表达式的参数,并计算整数表达式的值或在参数为空的情况下设置默认值。在这种情况下执行扩展\numexpr
但不进行空性测试似乎不合逻辑,我当时想用 进行测试\pdfstrcmp{}{...}
。这行不通。一个更丑陋但更正确的选择是:
\catcode`@=11
\def\evaluate#1{\expandafter\evaluate@\the\numexpr#1\z@\z@\relax}
\def\evaluate@#1\z@#2\relax{#1}
\evaluate{1+2+3}
\evaluate{\empty}
\evaluate{\@gobble\a}
\evaluate{`\a}
如果 的参数为\evaluate
空或扩展为空参数,则扩展\numexpr
将遍历所有内容并到达第一个\z@
,将其评估为0
(默认值),然后停止,因为\z@
在那里的整数表达式中没有意义。辅助清理。
另一方面,如果的参数\evaluate
是正确的整数表达式,则对其进行求值,并\numexpr
在遇到第一个时停止扩展\z@
,清理宏将删除两个\z@
。
我刚刚想到了一个更好的方法:“ f
-expand”(从左边完全扩展,在第一个不可扩展的标记处停止,如果是空格则删除它)在测试为空之前的参数:
\def\evaluate#1{\expandafter\evaluate@\expandafter{\romannumeral-`0#1}}
\def\evaluate@#1{\the\numexpr\ifcat X\detokenize{#1}X\z@\fi#1\relax}
如果参数为空或将扩展为空,\romannumeral-`0#1
则扩展为无,并且测试\evaluate@
为真,这意味着我们插入\z@
(默认值)。否则#1
进行评估。