在写入辅助文件之前扩展变量名称

在写入辅助文件之前扩展变量名称

在此链接的答案中,如何在写入 aux 文件时在变量名中拥有一个变量:https://tex.stackexchange.com/a/416272/192717

例如,来自上面的链接:

\edef\mysuffix{helloworld}
% define variable with variable suffix \mysuffix
\definevalue{tester\mysuffix}{42}

% and use it elsewhere
\usevalue{tester\mysuffix}

目前,我收到了这个可以理解的错误:

! Undefined control sequence.
<argument> usevalue@tester\mysuffix

l.37 ... \global \@namedef {tester\mysuffix }...

据我所知,如果我们能够扩展并在 aux 文件中写入变量名,问题就会得到解决,如下所示:

\global \@namedef {testerhelloworld }...

答案1

不要使用\unexpanded

\documentclass{article}

\makeatletter
\newcommand{\usevalue}[1]{%
  \ifcsname usevalue@#1\endcsname
    \csname usevalue@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\definevalue}[2]{%
  \begingroup\edef\x{\endgroup
    \write\@auxout{%
      \global\string\@namedef{usevalue@#1}{#2}%
    }%
  }\x
}
\makeatother

\def\mysuffix{helloworld}

\begin{document}

\usevalue{tester\mysuffix}

\definevalue{tester\mysuffix}{42}

\end{document}

这将打印“42”。

该文件的内容.aux

\relax 
\global \@namedef{usevalue@testerhelloworld}{42}

但是,只要你定义\mysuffix \begin{document}正如它应该。

\documentclass{article}

\makeatletter
\newcommand{\usevalue}[1]{%
  \ifcsname usevalue@#1\endcsname
    \csname usevalue@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\definevalue}[2]{%
  \write\@auxout{%
    \unexpanded{\global\@namedef{usevalue@#1}{#2}}%
  }
}
\makeatother

\newcommand{\mysuffix}{helloworld}

\begin{document}

Something with \usevalue{tester\mysuffix}.

Something else.

Now we can define \texttt{tester} and use again it: \usevalue{tester\mysuffix}.

\definevalue{tester\mysuffix}{42}

\end{document}

答案2

您可以实现类似于现有的LaTeX 2ε 内核机制的\label定义和检索值的基础结构。\ref

下面的示例提供了以下用户宏:

  • \valueundefinederror{⟨name of value⟩}

    如果值未定义,则触发错误消息,否则不执行任何操作。
    对应于\refusedHeiko Oberdiek 的 refcount 包。

  • \usevalue[{⟨tokens in case value is undefined⟩}]{⟨name of value⟩}

    如果没有提供可选参数,则 在值未定义的情况下传递。如果没有提供可选参数, 则对应于LaTeX 2ε-kernel。\valueundefinederror{⟨name of value⟩}\nfss@text{\reset@font\bfseries??}
    \ref

  • \usevalueexpandable{⟨name of value⟩}{⟨tokens in case value is undefined⟩}

    对应于 Heiko Oberdiek 的 refcount 包的 \getrefnumber。

  • \immediatedefinevalue{⟨name of value⟩}{⟨tokens to deliver when using the value⟩}

    几乎与LaTeX 2ε 内核的\def\@currentlabel{...}...相对应。 与 不同,立即完成 .aux 文件。)\label{...}
    \label\write

  • \definevalue{⟨name of value⟩}{⟨tokens to deliver when using the value⟩}

    对应于 LaTeX 2ε 内核的\def\@currentlabel{...}...。 与 一样,到 .aux 文件的操作也延迟完成。\label{...}
    \label\write

    既有和的扩展,也\immediatedefinevalue有形成标记的扩展\definevalue⟨tokens to deliver when using the value⟩⟨name of value⟩不是在将数据写入 .aux 文件时被阻止。

下面的示例提供了一些与 LaTeX 2ε 内核基础架构的挂钩,用于在值发生变化/未定义/多次定义时传递警告消息/错误消息。

\documentclass[landscape]{article}

\makeatletter
%%=====================================================================================
%% Layout of example document
%%=====================================================================================
\@ifundefined{pagewidth}{}{\pagewidth=\paperwidth}
\@ifundefined{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}
\@ifundefined{pageheight}{}{\pageheight=\paperheight}
\@ifundefined{pdfpageheight}{}{\pdfpageheight=\paperheight}
\textwidth=\paperwidth
\oddsidemargin=2.5cm
\advance\textwidth-2\oddsidemargin
\advance\oddsidemargin-1in
\evensidemargin=\oddsidemargin
\marginparwidth=1.5cm
\marginparsep=.5cm
\parindent=0ex
\parskip=\bigskipamount
\pagestyle{empty}%
%%=====================================================================================
\makeatother

\makeatletter
%%=====================================================================================
%% Switches and helper-macros for triggering error-messages/
%% warnings in case of undefined/multiply defined/changed values
%%=====================================================================================
\newif\if@valueschanged\global\@valueschangedfalse
\newcommand*\@valuesmultiplydefined{}%
\newcommand*\@valuesundefined{}%
\newcommand*\G@valueundefinedtrue{%
  \gdef\@valuesundefined{\@latex@warning@no@line{There were undefined values}}%
}%
%%=====================================================================================
%% \valueundefinederror{<name of value>}
%% Trigger error-message if value is undefined, else do nothing.
%% (Corresponds to \refused of Heiko Oberdiek's refcount-package.)
%%=====================================================================================
\newcommand\valueundefinederror[1]{%
  \@bsphack
  \begingroup
  \@ifundefined{usevalue@#1}{%
    \protect\G@valueundefinedtrue
    \@latex@warning{Value `#1' on page \thepage \space undefined}%
  }{}%
  \endgroup
  \@esphack
}%
%%=====================================================================================
%% \usevalue[{<tokens in case value is undefined>}]{<name of value>}
%%
%% If no optional argument is provided, 
%%   \valueundefinederror{<name of value>}\nfss@text{\reset@font\bfseries??}%
%% is delivered.
%% (Corresponds to \ref of the LaTeX2e-kernel if no optional argument is provided.)
%%=====================================================================================
\@ifdefinable\usevalue{%
  \DeclareRobustCommand\usevalue{\kernel@ifnextchar[{\@usevalue}{\@@usevalue}}%
}%
\@ifdefinable\@@usevalue{%
  \long\def\@@usevalue#1{\usevalueexpandable{#1}{\valueundefinederror{#1}\nfss@text{\reset@font\bfseries??}}}%
}%
\@ifdefinable\@usevalue{\long\def\@usevalue[#1]#2{\usevalueexpandable{#2}{#1}}}%
%%=====================================================================================
%% \usevalueexpandable{<name of value>}{<tokens in case value is undefined>}
%% (Corresponds to \getrefnumber of Heiko Oberdiek's refcount package.)
%%=====================================================================================
\newcommand{\usevalueexpandable}[2]{%
  \@ifundefined{usevalue@#1}{#2}{\csname usevalue@#1\endcsname}%
}%
%%=====================================================================================
%% \immediatedefinevalue{<name of value>}{<tokens to deliver when using the value>}
%% (Almost corresponds to \def\@currentlabel{...}...\label{...} of the LaTeX2e-kernel.
%%  Unlike with \label, the \write is done immediately.)
%%=====================================================================================
\@ifdefinable\immediatedefinevalue{%
  \DeclareRobustCommand{\immediatedefinevalue}{%
    \@definevalue{\immediate\write\@auxout}%
  }%
}%
%%=====================================================================================
%% \definevalue{<name of value>}{<tokens to deliver when using the value>}
%% (Corresponds to \def\@currentlabel{...}...\label{...} of the LaTeX2e-kernel.
%%  Like with \label, the \write is done delayed.)
%=====================================================================================
\@ifdefinable\definevalue{%
  \DeclareRobustCommand{\definevalue}{%
    \@definevalue{\let\thepage\relax\@@definevalue\@auxout}%
   }%
}%
\newcommand\@definevalue[3]{%
    \@bsphack
    \begingroup
    \let\protect\noexpand
    #1{\string\@valuedef{#2}{#3}}%
    \endgroup
    \if@nobreak\ifvmode\nobreak\fi\fi
    \@esphack
}%
\newcommand\@@definevalue[2]{\write#1{\unexpanded\expandafter{\expanded{#2}}}}%
%%%=====================================================================================
%% \@valuedef{<name of value>}
%% (Corresponds to \newlabel of the LaTeX2e-kernel.)
%%%=====================================================================================
\newcommand\@valuedef[1]{\@@valuedef{#1}{usevalue}}%
%%=====================================================================================
%% \@@valuedef{<name of value>}{<prefix for internal macros>}{<tokens to deliver when using the value>}
%% (Corresponds to \@newl@bel / \@testdef of the LaTeX2e-kernel.)
%%=====================================================================================
\newcommand\@@valuedef[3]{%
  \begingroup
  % Hashes were doubled while writing to \@auxout. Let's use a macro for halving them.
  \def\@tempa{#1}%
  \ifx\@newl@bel\@testdef\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
  {%
    \@ifundefined{#2@\@tempa}\relax{%
      \gdef\@valuesmultiplydefined{%
        \@latex@warning@no@line{There were multiply-defined values}%
      }%
      \@latex@warning@no@line{Value `\@tempa' multiply defined}%
    }%
    \global\@namedef{#2@\@tempa}{#3}%
  }{%
    \def\reserved@a{#3}%
    \expandafter\ifx\csname#2@\@tempa\endcsname\reserved@a
    \else
      \global\@valueschangedtrue
    \fi
  }%
  \endgroup
}%
%%=====================================================================================
%% This hooks into \@refundefined (which is executed by \enddocument)
%% for delivering messages in case of undefined/multiply defined/changed values:
%%=====================================================================================
\AtEndDocument{%
  \@ifundefined{@refundefined}\gdef\g@addto@macro\@refundefined{\valueschangedmessage}%
}%
\newcommand\valueschangedmessage{%
  \@valuesundefined
  \if@filesw 
  \ifx\@valuesmultiplydefined\@empty
    \if@valueschanged
      \@latex@warning@no@line{Value(s) may have changed. Rerun to get value(s) right}%
    \fi
  \else
    \@valuesmultiplydefined
  \fi
  \fi
}%
%%=====================================================================================
\makeatother

\begin{document}

\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{Let's see the meaning
of the underlying macro:}}

\makeatletter
\verb|\meaning\usevalue@testerhelloworld|: \texttt{\meaning\usevalue@testerhelloworld}
\makeatother

\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{Now let's use the 
unexpandable variant with the optional argument which by default does trigger
(unexpandable) error-messages in case of the value not being defined/available:}}

\underline{Here \texttt{\string\mysuffix} is not yet defined:}

\verb|\usevalue{testerhelloworld}|: \usevalue{testerhelloworld}

\underline{Here \texttt{\string\mysuffix} is defined:}

\def\mysuffix{helloworld}%
\verb|\def\mysuffix{helloworld}| $\to$ \texttt{\string\mysuffix:\ \meaning\mysuffix}

\verb|\usevalue{tester\mysuffix}|: \usevalue{tester\mysuffix}

\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{Now let's use the
expandable variant which does not trigger (unexpandable) error-messages
in case of the value not being defined/available:}}

Trigger the error-message about the value being undefined ``by hand'' if necessary:

\verb|\valueundefinederror{tester\mysuffix}|
\valueundefinederror{tester\mysuffix}

Perform something within an expansion-context where non-expandable things would disturb:

\verb|Value \texttt{tester\mysuffix} is \ifnum\usevalueexpandable{tester\mysuffix}{-1}=-1 un\fi defined.|:\\
Value {\tt tester\string\mysuffix} is \ifnum\usevalueexpandable{tester\mysuffix}{-1}=-1 un\fi defined.

\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{Here the value \texttt{testerhelloworld} is
defined in terms of \texttt{\string\mysuffix}:}}

\verb|\immediatedefinevalue{tester\mysuffix}{42}|%
\immediatedefinevalue{tester\mysuffix}{42}%

\end{document}

在此处输入图片描述

相关内容