如何定义一个声明 fancyref 前缀的宏?如何阻止它输出文本?

如何定义一个声明 fancyref 前缀的宏?如何阻止它输出文本?

在 LaTeX 文档中,我使用fancyref软件包进行文档内引用。但是,我需要一堆自定义前缀来引用引理、定义和定理,而 fancyref 不提供这些。按照文档,添加一个支持两者的前缀,需要大量vario文本,而且一直都一样。我想使用宏来避免这种情况,宏可以帮我完成所有工作,但我被它难住了。plainfrefFref

这是我目前的尝试:

\documentclass[a4paper]{article}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[english]{babel}
\usepackage[plain]{fancyref}

% command to define a fancyref prefix
\makeatletter
\def\mkfancyprefix#1#2{%
  \@namedef{fancyref#1labelprefix}{#1}%
  \frefformat{plain}{\@nameuse{fancyref#1labelprefix}}{%
    \MakeLowercase{#2}\fancyrefdefaultspacing##1%
  }%
  \Frefformat{plain}{\@nameuse{fancyref#1labelprefix}}{%
    #2\fancyrefdefaultspacing##1%
  }%
}
\makeatother

% environments and references for lemmas, ...
\newtheorem{lemma}{Lemma}
\mkfancyprefix{lem}{Lemma}

% content
\begin{document}
\begin{lemma}
\label{lem:lemma}
This is a Lemma
\end{lemma}
There's \fref{lem:lemma} around! \Fref{lem:lemma} is the same, but at the beginning of a sentence.
\end{document}

但是,这无法编译,并抱怨:

Missing \begin{document}

如果我移动\mkfancyprefix{lem}{Lemma}之后\begin{document},我可以看到它实际上输出了fancyreflemlabelprefixfancyreflemlabelprefix。除此之外,一切都正常并且看起来符合预期。

这让我很困惑,为什么命令会将 的扩展参数打印\@nameuse到文档中?我做了一些实验,并\expandafter在 两次出现 之前立即添加了\@nameuse。这会将输出更改为lemlem,但这并没有减少我的困惑。

为什么会这样?我该如何防止?

附录:
Enrico 提供 对我下面的问题有很好的回答。稍微扩展一下,就会得到一个命令,它fancyref在格式变体vario和中声明一个新的前缀plain。如果你使用其他的(比如main),你必须相应地扩展宏。

\makeatletter
\def\mkfancyprefix#1#2{%
\expandafter\def\csname fancyref#1labelprefix\endcsname{#1}%
% plain lowercase
\begingroup\def\x{\endgroup\frefformat{plain}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
    {\MakeLowercase{#2}\fancyrefdefaultspacing##1}%
% plain uppercase
\begingroup\def\x{\endgroup\Frefformat{plain}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
    {#2\fancyrefdefaultspacing##1}%
% vario lowercase
\begingroup\def\x{\endgroup\frefformat{vario}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
    {\MakeLowercase{#2}\fancyrefdefaultspacing##1##3}%
% vario uppercase
\begingroup\def\x{\endgroup\Frefformat{vario}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
    {#2\fancyrefdefaultspacing##1##3}%
}
\makeatother

答案1

问题是,\frefformat期望它的第二个参数是一个控制序列,而不是生成控制序列的指令;所以你必须在 TeX 看到之前构建标记\frefformat

\makeatletter
\def\mkfancyprefix#1#2{%
  \@namedef{fancyref#1labelprefix}{#1}%
  \begingroup\def\x{\endgroup\frefformat{plain}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
      {\MakeLowercase{#2}\fancyrefdefaultspacing##1}%
  \begingroup\def\x{\endgroup\Frefformat{plain}}%
    \expandafter\x\csname fancyref#1labelprefix\endcsname
      {#2\fancyrefdefaultspacing##1}%
}
\makeatother

诀窍\x就是能够使用\expandafter

它是如何工作的?当\mkfancyprefix{lem}{Lemma}被调用时,TeX 会

\@namedef{fancyreflemlabelprefix}{lem}

相当于\def\fancyreflemlabelprefix{lem}。然后它会找到

\begingroup\def\x{\endgroup\frefformat{plain}}%
  \expandafter\x\csname fancyreflemlabelprefix\endcsname
    {\MakeLowercase{Lemma}\fancyrefdefaultspacing#1}

(现在##1定义中的变成了应该的样子)。执行 之后,LaTeX 仍然有一个待处理项,并发现,因此它会扩展(一次),从而产生标记。接下来会进行扩展,因此 TeX 面临\mkfancyref#1\def\x{...}\begingroup\expandafter\x\csname fancyreflemlabelprefix\endcsname\fancyreflemlabelprefix\x

\endgroup\frefformat{plain}\fancyreflemlabelprefix
  {\MakeLowercase{Lemma}\fancyrefdefaultspacing#1}

匹配\endgroup仍然待处理的\begingroup并从内存中删除的定义\x;然后正确的\frefformat指令就可以被处理了。

相关内容