\numexpr...\relax 与 \pdfstrcmp 的扩展

\numexpr...\relax 与 \pdfstrcmp 的扩展

eTeX 中的构造\numexpr...\relax允许评估数值表达式,并且它会在进行过程中完全扩展标记。

pdfTeX 中的构造\pdfstrcmp{...}{...}让我们可以在完全扩展并转换为字符串(使用\detokenize)之后比较两个标记列表。

是否存在特定的标记列表(无参数宏)\foo,可以\the\numexpr\foo\relax正确生成整数,但\pdfstrcmp{\foo}{}会导致 TeX 错误? 似乎两种情况下的扩展行为相同,但一种将其参数转换为整数,另一种将其参数转换为字符串。

答案1

我看到两种情况,其中\the\numexpr...\relax有效,但\pdfstrcmp{}{...}会爆炸,不包括明显的...被替换的情况0\relax\undefined,过早终止\numexpr

  1. TeX 将其解释`\a为数字,而不扩展\a。因此,\the\numexpr`\a\relax扩展为97( 的字符代码a),而如果未定义,\pdfstrcmp{}{`\a}则会爆炸。\a

  2. 使用\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进行评估。

相关内容