脆弱命令的输出可以是超链接地址吗?

脆弱命令的输出可以是超链接地址吗?

这个问题导致了一个新的方案的出现:
bibleref-mouth

我正在尝试编写一个带有可选参数的命令,并将输出提供给该\url命令。我的动机是使用bibleref包。该包已经定义了一个带有可选参数的 API,所以我不想更改语法。

\url{\bibleverseurl{Amos}(3:7)}

但带有可选参数的命令显然太脆弱,无法被使用\url。故事在我的示例代码中。

\documentclass{article}

\usepackage{makerobust}
\usepackage{hyperref}[2011/04/09 v6.82f]

% Macro that takes an argument and encloses it in angle brackets
\protect\def\parenmatch(#1){%
    MATCH$\langle#1\rangle$%
}

% Macro that does not take an argument
\protect\def\parenmismatch{%
    MISMATCH%
}

% Check whether there is a parenthesis in the input, then call
% \parenmatch or \parenmismatch
\makeatletter
\newcommand*{\matcher}{%
    \@ifnextchar{(}%
        \parenmatch%
        \parenmismatch%
}
\makeatother

% The \matcher command is probably fragile, so try to make it robust.
% Actually, I found that \matcher behaves identically to \robustmatcher
% in the examples below.
\DeclareRobustCommand{\robustmatcher}{\matcher}

\begin{document}

% This line correctly produces: MATCH<arg>
\robustmatcher(arg)

% This line correctly produces: MISMATCH!
\robustmatcher!

% This block emits an error: ! Use of \parenmatch doesn't match its definition.
% If I loosen the restrictions on the \parenmatch arguments, it
% only produces a different warning: ! Missing control sequence inserted.
% The evaluation does not respect protected commands, so it either fails to
% compile or it creates incorrect output.
% A better option is below.
\edef\problem{\robustmatcher()}
\problem

% This block correctly produces: MATCH<arg>
% As long as I use \protected@edef instead of \edef, it compiles successfully.
\makeatletter
\protected@edef\captured{\robustmatcher(arg)}
\makeatother
\captured

% Now I would like to use the command output as a link target.
% This was my goal all along.
% But the link doesn't have the address I would expect. It shows in the document as:
%   \protect\let\reserved@d=(\def\defMISMATCH{MISMATCH}\futurelet\@let@token\letMATCH$\delimiter"426830Aarg\delimiter"526930B$
% I tried sprinkling \protect and \expandafter commands in the definitions and
% applications, but nothing has helped.
\url{\captured}

\end{document}

有什么事情hyperref会使这一切变得不可能吗?我希望能够以某种方式重新排序求值,以便可以\url安全地传递已扩展的纯字符串。

答案1

您面临的问题是无法以可扩展的方式解析可选参数。因此,\url永远不会看到宏的扩展。在最好的情况下(即,如果宏变得健壮),宏根本不会扩展,在最坏的情况下,它们会部分扩展,并且通常会出现一些! Undefined control sequence错误。

因此,最好的办法是将\url命令放在最终宏内,而不是放在宏周围。这样,带有可选参数的命令就“超出”了所有其他命令,并且可以按您的意愿不扩展。

\documentclass{article}
\usepackage{hyperref}[2011/04/09 v6.82f]
\def\urlmatcher{\@ifnextchar{(}\urlparenmatch\urlparenmismatch}
\def\urlparenmatch(#1){\url{MATCH(#1)}}
\def\urlparenmismatch{\url{MISMATCH!}}
\begin{document}
\urlmatcher Hello, world!
\urlmatcher(arg)   
\end{document}

为了帮助您调试,您可以使用\show,非常有用的 TeX 原语(用作例如\show\urlmatcher,或在您的示例中,\show\captured)。我有时也使用\tracingall

相关内容