def 中的 def 与 ref 一起使用时会出现错误

def 中的 def 与 ref 一起使用时会出现错误

我想定义一个命令,该命令返回一个与 一起使用的标签\ref,但它需要使用 \edef 来扩展另一个命令。但是,我遇到了几个以 开头的错误,这些错误来自Missing \endcsname inserted.以下 M(not)WE:

\documentclass{article}

\begin{document}
\begin{equation}
  \label{eq:test-10}
  A=B
\end{equation}

\def\test#1{%
  \edef\arg{test}%
  \arg-#1}

This works \test{10}. But this doesn't \ref{eq:\test{10}}.
\end{document}

我也尝试过 \ref\expandafter{eq:\test{10}} ,但结果出现了错误 File ended while scanning use of \@setref.

我显然误解了有关扩展的一些基本知识,有人可以解释一下吗?有办法解决吗?

编辑:正如回复者所问,这是我的(不是那么简单的)用例。获取标签的命令有点复杂

\documentclass{article}

\makeatletter
\def\mytest#1{\@mytest#1--\relax}
\def\@stripdashes#1-#2\relax{#1}

\def\@mytest#1-#2-#3\relax{%
  \edef\@arg@third{\@stripdashes#3-\relax}%
  \ifx\@arg@third\empty%
    % No year
    \if\relax\detokenize{#2}\relax%
      % No month
      ONE-TWO-#1%
    \else%
      ONE-#1-#2%
    \fi%
  \else#1-#2-\@arg@third\fi%
}
\makeatother

\begin{document}
\begin{equation}
  \label{eq:ONE-TWO-3}
  A=B
\end{equation}

This works: \mytest{3}, \mytest{TWO-3}

But not this:
\ref{\mytest{3}}, \ref{\mytest{TWO-3}}

\end{document}

实际上,ONE 和 TWO 是动态构建标签的其他命令。

答案1

当 LaTeX 处理时,\ref{foo}它基本上会查看控制序列是否\r@foo被定义(用@字母),并且为了做到这一点,它会执行

\csname r@foo\endcsname

里面的标记\csname...\endcsname必须扩展为字符标记。在你的情况下,LaTeX 会尝试

\csname r@eq:\test{10}\endcsname

\test扩大到

\csname r@eq:\edef\arg{10}\endcsname

这是违法的。你不能在里面执行宏定义\csname...\endcsname,确实,Missing \endcsname只要\edef扫描到,你就会得到结果。TeX 现在尝试通过\endcsname在有问题的标记前面插入来恢复,但显然这会导致其他实际上毫无意义的错误。

对于您的用例(在我给出上述答案后解释),定义\@test參數。

\documentclass{article}

\makeatletter
\def\mytest#1{eq:\@mytest#1---\@nil}

\def\@mytest#1-#2-#3-#4\@nil{%
  \if\relax\detokenize{#3}\relax
    % No year
    \if\relax\detokenize{#2}\relax
      % No month
      ONE-TWO-#1%
    \else
      ONE-#1-#2%
    \fi
  \else
    #1-#2-#3%
  \fi
}
\makeatother

\begin{document}
\begin{equation}
  \label{eq:ONE-TWO-3}
  A=B
\end{equation}

This works: \mytest{3}, \mytest{TWO-3}, \mytest{ONE-TWO-3}

But not this:
\ref{\mytest{3}}, \ref{\mytest{TWO-3}}, \ref{\mytest{ONE-TWO-3}}

\end{document}

在此处输入图片描述

答案2

该参数需要扩展为标签名称,因此删除分配:

\documentclass{article}

\begin{document}
\begin{equation}
  \label{eq:test-10}
  A=B
\end{equation}

\def\test#1{%
  test-#1}

This works \test{10}. But this doesn't \ref{eq:\test{10}}.
\end{document}

以上工作如预期。


这里没有什么特别的\ref;例如,你会看到同样的失败

\setcounter{section}{\def\tmp{2}\tmp}

或者

\setcounter{\def\tmp{section}\tmp}{2}

\setcounter需要扩展到计数器名称和<number>但分配到的参数随后\tmp扩展\tmp可能打印作为部分名称或数字(或标签名称),但它不能通过扩展来发挥作用。


稍后添加到问题的扩展版本是类似的,您只需要使用可扩展测试,就像#3您已经做的那样#1(更复杂的情况可以使用\expanded(或 expl3e参数)而不是\edef(expl3x参数),但这里根本不需要。

\documentclass{article}

\makeatletter
\def\mytest#1{\@mytest#1---\relax}

\def\@mytest#1-#2-#3-#4\relax{%
  eq:% missing from example in question here or in the `\ref`
  \if\relax\detokenize{#3}\relax
    % No year
    \if\relax\detokenize{#2}\relax
      % No month
      ONE-TWO-#1%
    \else%
      ONE-#1-#2%
    \fi%
  \else#1-#2-#3%
\fi
}
\makeatother

\begin{document}
\begin{equation}
  \label{eq:ONE-TWO-3}
  A=B
\end{equation}

This works: \mytest{3}, \mytest{TWO-3}

But not this:
\ref{\mytest{3}}, \ref{\mytest{TWO-3}}

\end{document}

相关内容