“可扩展上下文”中的信号错误

“可扩展上下文”中的信号错误

我正在检查我的一些旧宏,使它们完全可扩展。其中一个宏接受一个参数,该参数应该是两位数或四位整数(>1955)。然后,该宏将两位数转换为 1956-2055 范围内的四位年份,然后继续执行其他操作(基本上基于当前年份和给定年份之间的差异)。我想让它可扩展,因为我希望能够在例如中使用它。\href{mailto:foo\mymacro{98}[email protected]}{Mail me!}

现在,回顾代码,我可以看到我使用了很多作业,但是使用\numexpr我可以摆脱所有这些,尽管当我分支不同的情况时需要多次进行相同的计算。

但我以前也做过一些健全性检查:如果#1大于 99 但小于 1956,我会发出一个\PackageError解释问题的代码。如果健全性检查成立,则直接跳过,因此其不可扩展性不是问题。此外,在普通文本中使用时,错误会按预期工作。然而,在 内部\href,错误变为

Undefined control sequence.
\GenericError  ...                                
                                    #4  \errhelp \@err@     ...

这没有什么帮助。

有没有办法向用户提示问题所在?

附言:我不确定“可扩展上下文”是否适合描述这种情况。欢迎提出更好的标题。

编辑:例如,假设我想\mymacro扩展给定年份和之间的差值的绝对值\year。如果输入小于 100,我们应该将其解释为 1956-2055 范围内的年份。输入 100-1955 范围内的年份应该会出错。我现在得到的是

\def\mymacro#1{%
  \ifnum\numexpr#1>1955 %
    \ifnum\numexpr\year-#1\relax<0 %
      \number\numexpr#1-\year\relax
    \else
      \number\numexpr\year-#1\relax
    \fi
  \else
    \ifnum#1>99 %
      ERROR!%
    \else
      \ifnum#1>56 % 19xx
        \number\numexpr\year - 19#1\relax
      \else % 20xx
        \ifnum\numexpr\year - 20#1\relax<0 
          \number\numexpr20#1 - \year\relax
        \else
          \number\numexpr\year - 20#1\relax
        \fi
      \fi
    \fi
  \fi
}

%\def\test#1{#1: a\mymacro{#1}b}
\def\test#1{#1: \href{http://a\mymacro{#1}b}{Link}}
\test{96} \test{1996}; \test{08} \test{2008}; \test{11} \test{2011};
\test{20} \test{2020}

\test{123}

(a 和 b 只是用来检查空格是否悄悄出现)。所以我想用一些可以告诉用户问题的信息来替换 ERROR!,最好使用包含有问题的消息#1

答案1

我认为这是不可能的,因为的扩展\mymacro应该始终可以被解释为\href链接,但\PackageError事实并非如此。

\href您可以通过检查的 catcode 是否%为 13 来测试您是否在的参数内部:

\ifnum\catcode`\%=\active\else\PackageError{...}{...}{...}\fi

但我不知道这段代码的健壮性如何。你能展示一下代码的相关部分吗?

答案2

我认为最好的方法是使用故意未定义但命名良好的控制序列。例如

\ifnum\SomeVar>100\relax
  \expandafter\SignalError
\fi

...

\begingroup
\catcode`\!=11\relax
\catcode`\ =11\relax%
\gdef\SignalError{%
  \ Input too big!%
}%
\endgroup%

使用 catcode 11 空间完成后,您将收到一个错误,该错误至少有一些描述,但不会在内部崩溃\edef。您可能需要调整使用的字母数量以使其看起来“漂亮”,但这通常不太难。

答案3

与约瑟夫的回答类似,但允许任何错误消息(我很快会在一个包中使用它,我会尝试使它对错误输入非常稳健)。

\makeatletter
\catcode`\:=11\relax
\newcommand{\fp@error@aux}[1]
  {\romannumeral \numexpr 0\@firstofone{\fp@error: #1}}
\newcommand{\fp@error}[1]
  {\expandafter\fp@error@aux\csname fp info: #1\endcsname}

\fp@error{wrong input (123)}

给予

! Undefined control sequence.
<argument> \fp@error: 
                      \fp info: wrong input (123) 

这里,从和\csname fp info: #1\endcsname之间的字符构建一个控制序列。TeX 不会让它保持未定义状态:相反,它会变成,这不会导致错误。相反,我们在附近放置了一个未定义的控制序列。改进了错误消息的格式,因为未定义的控制序列现在与 -ed 控制序列一起出现在 中。最后,我们需要一种干净的方法来摆脱,并且在这方面做得很好。\csname\endcsname\relax\@firstofone\fp@error:\relax<argument>\relax\romannumeral\numexpr0

编辑:在回答这个问题几个月后,我们将其添加\msg_expandable_error:n到 LaTeX3。此命令接受一个(带括号的)参数并显示它(不展开它)。如果用户插入一些材料(响应I...TeX 的提示),则在清理错误消息后插入该材料。

答案4

您可以定义\mymacro当参数超出范围时扩展为空,并将其包装\href在一个测试是否为空的宏中。

\documentclass{article}
\usepackage{hyperref}

\def\mymacro#1{%
  \ifnum\numexpr#1>1955 %
    \ifnum\numexpr\year-#1\relax<0 %
      \number\numexpr#1-\year\relax
    \else
      \number\numexpr\year-#1\relax
    \fi
  \else
    \ifnum#1>99 %
      % out-of-range error!
    \else
      \ifnum#1>56 % 19xx
        \number\numexpr\year - 19#1\relax
      \else % 20xx
        \ifnum\numexpr\year - 20#1\relax<0 
          \number\numexpr20#1 - \year\relax
        \else
          \number\numexpr\year - 20#1\relax
        \fi
      \fi
    \fi
  \fi
}

\begin{document}
%\def\test#1{#1: a\mymacro{#1}b}
\def\test#1{#1: \href{http://a\mymacro{#1}b}{Link}}
\test{96} \test{1996}; \test{08} \test{2008}; \test{11} \test{2011};
\test{20} \test{2020}

\def\hrefwrap#1{\def\tmpi{\mymacro{#1}}\if\relax\tmpi\relax 
\typeout{error! (#1 out of range)}ERROR\footnote{#1 out of range}\else
\href{http://a\tmpi b}{Link}\fi}

\def\testi#1{#1: \hrefwrap{#1}}

\testi{96} \testi{1996}; \testi{08} \testi{2008}; \testi{11} \testi{2011};
\testi{20} \testi{2020}
\testi{123}

%\the\year
\end{document}

相关内容