首先,我要为下面的 MWE 太长而道歉。但是,我想让它保持完整。
归根结底,我想实现像这样的构造$H^{\ref*{my-label}}_{\ref*{another-label}}$
。使用星号变体,因为hyperref
已加载,并且我不需要数学公式中的超链接。
不幸的是,\ref*{my-label}
它不只是简单地扩展为一个数字,而是更复杂的东西,可能太复杂了。如果有人对下面的 MWE 有一个更简洁、更简单的解决方案,我很高兴听到这个消息。
在当前方法中,\ref*{my-label}
将其扩展为两个标记{roman numeral}{arabic numeral}
,并且首先需要分离组件。我无法使其工作,并且由于\protect
的定义内部而迷失了方向\ref
。
要查看错误,请从 MWE 中的方程环境中删除注释。
{roman numeral}{arabic numeral}
此外,如果能找到一种解决方案,可以放弃使用人工构建标签的丑陋解决方法,并可能向辅助文件中写入额外的一行,我会很高兴。我的整个代码感觉像是一个黑客代码。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[utf8]{inputenc}
\usepackage[hyperref]{ntheorem}
\usepackage[unicode,final]{hyperref}
\usepackage{cleveref}
\input{glyphtounicode}
\pdfgentounicode=1
%
% How the hybrid mechanism works
%
% Hybrids are defined by a theorem-like environment call "hybrid" using the counter \c@hybrid.
% Hybrids can be grouped into series.
% To make the reference unique, series are also counted using \c@hybridseries.
% Each time \c@hybridseries is advanced, \c@hybrid is reset.
% Series have a human-readable name.
%
% A hybrid should be printed as "H^{human-readable series name}_{hybrid counter}".
% To make this work correctly we need a little bit of trickery, because LaTeX writes the printable
% form of a label to the aux-file and not the plain values of the counters.
% Also, the "public" API of ntheorem and cref use the printable form of the counters.
%
% Under the hood the counter on the level of hybrid is internally formatted as
%
% "{roman number of series}{arabic numer of hybrid}"
%
% The series counter is formatted as a roman number, because this allows to construct TeX macros that include the counter in their name.
% For example, \@hybridseriesnameiii expands to the human-readable name of the 3rd series.
% For convinience, there is the helper macro \@hybridseriesname{#1}.
% It takes the roman counter of a series as its only argument and constructs the makro \@hybridseriesname<#1>, i.e. eventually it is expanded to the human-readable name.
%
\makeatletter
%
% The counter for the series formatted as a roman number
%
\newcounter{hybridseries}
\renewcommand{\thehybridseries}{\romannumeral\c@hybridseries}
%
% A helper macro that expands to \hybridseriesname#1, e.g. \hybridseriesname{iii} expands to \hybridseriesnameiii
%
% #1 The series formatted as a roman number
%
\newcommand\@hybridseriesname[1]{%
\csname @hybridseriesname#1\endcsname%
}
%
% Advances the series counter \c@hybridseries and defines a new command \hybridseriesname<counter>, e.g. \hybridseriesnameiii, that stores the human-readable name.
%
% #1 The human-readable name of the series; n.b., #1 is printed in math mode, hence, if it is a textual name, #1 should most probably something like \text{...} or \mathrm{...}
%
\newcommand{\newhybridseries}[1]{%
\stepcounter{hybridseries}%
\setcounter{hybrid}{-1}%
\expandafter\def\csname @hybridseriesname\thehybridseries\endcsname{#1}%
}
%
% \@hyb takes an internally formatted counter value
% {roman number of series}{arabic numer of hybrid}
% and expand to "H^{human-readable series name}_{hybrid counter}".
% The first part {roman number of series} is passed to \@hybridseriesname to convert it into the human-readable name.
% The second part {arabic number of hybrid} is used as is.
%
\newcommand{\@hyb}[2]{%
H^{\@hybridseriesname{#1}}_{#2}%
}
%
% \hyb takes a the designation of a label and expands to "H^{human-readable series name}_{hybrid counter}.
% \hyb is supposed to be used in math mode.
%
\newcommand{\hyb}[1]{%
\@expand@hyb{\ref*{#1}}%
}
%
% A helper macro in the spirit of \@expandtwoargs from the LaTeX2e sources
%
% #1 is a token that ultimately expands into two tokens
% {roman number of series}{arabic numer of hybrid}
%
% This macro first expands #1 and then lets \@hyb process the expanded #1
%
\def\@expand@hyb#1{%
\edef\reserved@hyb{\noexpand\@hyb #1}%
\reserved@hyb%
}
%
% This theorem style is mostly equivalent to the plain style.
% But the counter (##2) is passed to \@hyb such that is nicely printed as
% "H^{human-readable series name}_{hybrid counter}"
% and not as
% {roman number of series}{arabic numer of hybrid}
%
% ##1 Printable name (e.g. Theorem, Lemma, etc.); here this always equals "Hybrid"
% ##2 Printable and internally formatted counter value, i.e. {roman number of series}{arabic numer of hybrid}
% ##3 Optional decription
\newtheoremstyle{@hybridstyle}{%
\item[\hskip\labelsep \theorem@headerfont ##1\ $\@expand@hyb{##2}$\theorem@separator]%
}{%
\item[\hskip\labelsep \theorem@headerfont ##1\ $\@expand@hyb{##2}$\ (##3)\theorem@separator]%
}
%
% Defines the hybrid-enviroment
% Uses the special @hybridstyle, make the counter \c@hybrid subordinate to \c@hybridseries and formats \c@hybrid as
% {roman number of series}{arabic numer of hybrid}
%
\theoremstyle{@hybridstyle}
\theoremheaderfont{\normalfont\bfseries}
\theoremseparator{}
\theorembodyfont{\normalfont\itshape}
\theoremsymbol{}
\newtheorem{hybrid}{Hybrid}[hybridseries]
\renewcommand{\thehybrid}{{\thehybridseries}{\number\c@hybrid}}
%
% Defines name and label format for cleveref.
% Again, the formatted counter #1 is passed to \@hyb such that is nicely printed as
% "H^{human-readable series name}_{hybrid counter}"
% and not as
% {roman number of series}{arabic numer of hybrid}
%
\crefname{hybrid}{hybrid}{hybrids}
\Crefname{hybrid}{Hybrid}{Hybrids}
\creflabelformat{hybrid}{#2$\@expand@hyb{#1}$#3}
\makeatother
\begin{document}
To prove security, we define a sequence of hybrids first.
\newhybridseries{\mathrm{security}}
\begin{hybrid}[Foo]\label{hyb:sec-foo}
This \namecref{hyb:sec-foo} modifies \ldots
\end{hybrid}
\begin{hybrid}[Bar]\label{hyb:sec-bar}
Didel di dum
\end{hybrid}
We now show the indistinguishability of these hybrids, i.e. we show that
% TODO: Does not work.
%\begin{equation}
% \hyb{hyb:sec-foo} \equiv \hyb{hyb:sec-bar}
%\end{equation}
holds.
Privacy is also proven by a sequence of hybrds.
\newhybridseries{\mathrm{privacy}}
\begin{hybrid}[Foobar]\label{hyb:priv-foobar}
As in \cref{hyb:sec-foo}, this \namecref{hyb:priv-foobar} also \ldots
\end{hybrid}
\begin{hybrid}[Foo]\label{hyb:priv-foo}
Didel di dum
\end{hybrid}
\begin{table}[hbtp]\centering%
\begin{tabular}{l c c c}
Label & \texttt{ref} & \texttt{labelcref} & \texttt{cref} \\
\texttt{hyb:sec-foo} & \ref{hyb:sec-foo} & \labelcref{hyb:sec-foo} & \cref{hyb:sec-foo}\\
\texttt{hyb:sec-bar} & \ref{hyb:sec-bar} & \labelcref{hyb:sec-bar} & \cref{hyb:sec-bar}\\
\texttt{hyb:priv-foobar} & \ref{hyb:priv-foobar} & \labelcref{hyb:priv-foobar} & \cref{hyb:priv-foobar}\\
\texttt{hyb:priv-foo} & \ref{hyb:priv-foo} & \labelcref{hyb:priv-foo} & \cref{hyb:priv-foo}
\end{tabular}%
\caption{Test of References and Labels}%
\end{table}
\end{document}
答案1
我终于找到了解决方案。从健壮性的角度来看,它可能不是最好的解决方案,因为它依赖于hyperref
写入辅助文件的格式。
该宏\hyb
需要定义为
\newcommand{\hyb}[1]{%
\expandafter\ifx\csname r@#1\endcsname\relax%
\@latex@warning{Reference `#1' on page \thepage \space undefined}%
\mathbf{??}%
\else%
\@expand@hyb{\expandafter\expandafter\expandafter\@firstoffive\csname r@#1\endcsname}%
\fi%
}
代替
\newcommand{\hyb}[1]{%
\@expand@hyb{\ref*{#1}}%
}
我首先解释为什么原始方法失败,然后解释最终解决方案的工作原理。\@expand@hyb
期望它的参数(此处:)可以在这两个标记被使用之前\ref*{#1}
扩展为两个标记。但是,是不可扩展的,因为它在内部使用。{roman value of \c@hybridseries}{arabic value of \c@hybrid}
\@hyb
\ref*{#1}
\protect
所提出的解决方案或多或少是 的内联版本\ref*
(没有 hyperref-magic),从而避免了有问题的\protect
。让我从解决方案的 else-branch 开始,这是“好”的情况。当通过以下示例创建新标签时,\label{my-label}
行将插入到辅助文件中
\newlabel{my-label}{{{i}{1}}{1}{}{hybrid.1.1}{}}
(Nb 在此示例中,系列计数器等于 i,而混合计数器等于 1。)当再次重新读取辅助文件时,\newlabel
将宏定义\r@my-label
为{{i}{1}}{1}{}{hybrid.1.1}{}
。在外层,这些是五个标记,第一个标记是两个标记的组{i}{1}
。(Nb,hyperref 导致这五个标记,如果没有 hyperref,则只有两个。但请注意,这\r@my-label
不是通常有效的宏名称,只能由构造\csname
。)
现在,\hyb
工作原理如下。它\r:my-label
通过构造宏\csname r@#1\endcsname
。然后\@firstoffive
(来自 hyperref 包的内部宏)删除除第一个标记之外的所有标记,即{i}{1}
剩余的标记。这些被传递给\@expand@hyb
,最终扩展为\@hyb{i}{1}
。
\expandafter
需要三个 的序列才能获得正确的扩展顺序。在执行 之前,必须构造\@firstoffive
宏,即必须首先执行 。这会产生最正确的。但是不能应用于。后者将只是一个标记,而不是五个。相反,还必须扩展一次。这会产生另外两个。\r@my-label
\csname
\expandafter
\@firstoffive
\r@my-label
\r@my-label
\expandafter
\ifx
--构造\else
断言\fi
实际上#1
表示现有标签或已打印警告。
答案2
重新定义\hyb
为使用\getrefnumber
,如
\newcommand{\hyb}[1]{%
\@expand@hyb{\getrefnumber{#1}}%
}
似乎允许代码(包括方程式)编译。J Kormylo 在去年的评论中提到了这一点。根据我有限的理解,该方程式似乎产生了所需的结果。
我唯一能确定的问题是,\newhybridseries
必须先定义一个系列,然后才能将其用于\hyb
引用。因此,例如,如果在方程式 1 之前已发布,则\hyb{hyb:priv-foo}
只能在方程式 1 中使用。\newhybridseries{\mathrm{privacy}}
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[utf8]{inputenc}
\usepackage[hyperref]{ntheorem}
\usepackage[unicode,final]{hyperref}
\usepackage{cleveref}
\input{glyphtounicode}
\pdfgentounicode=1
%
% How the hybrid mechanism works
%
% Hybrids are defined by a theorem-like environment call "hybrid" using the counter \c@hybrid.
% Hybrids can be grouped into series.
% To make the reference unique, series are also counted using \c@hybridseries.
% Each time \c@hybridseries is advanced, \c@hybrid is reset.
% Series have a human-readable name.
%
% A hybrid should be printed as "H^{human-readable series name}_{hybrid counter}".
% To make this work correctly we need a little bit of trickery, because LaTeX writes the printable
% form of a label to the aux-file and not the plain values of the counters.
% Also, the "public" API of ntheorem and cref use the printable form of the counters.
%
% Under the hood the counter on the level of hybrid is internally formatted as
%
% "{roman number of series}{arabic numer of hybrid}"
%
% The series counter is formatted as a roman number, because this allows to construct TeX macros that include the counter in their name.
% For example, \@hybridseriesnameiii expands to the human-readable name of the 3rd series.
% For convinience, there is the helper macro \@hybridseriesname{#1}.
% It takes the roman counter of a series as its only argument and constructs the makro \@hybridseriesname<#1>, i.e. eventually it is expanded to the human-readable name.
%
\makeatletter
%
% The counter for the series formatted as a roman number
%
\newcounter{hybridseries}
\renewcommand{\thehybridseries}{\romannumeral\c@hybridseries}
%
% A helper macro that expands to \hybridseriesname#1, e.g. \hybridseriesname{iii} expands to \hybridseriesnameiii
%
% #1 The series formatted as a roman number
%
\newcommand\@hybridseriesname[1]{%
\csname @hybridseriesname#1\endcsname%
}
%
% Advances the series counter \c@hybridseries and defines a new command \hybridseriesname<counter>, e.g. \hybridseriesnameiii, that stores the human-readable name.
%
% #1 The human-readable name of the series; n.b., #1 is printed in math mode, hence, if it is a textual name, #1 should most probably something like \text{...} or \mathrm{...}
%
\newcommand{\newhybridseries}[1]{%
\stepcounter{hybridseries}%
\setcounter{hybrid}{-1}%
\expandafter\def\csname @hybridseriesname\thehybridseries\endcsname{#1}%
}
%
% \@hyb takes an internally formatted counter value
% {roman number of series}{arabic numer of hybrid}
% and expand to "H^{human-readable series name}_{hybrid counter}".
% The first part {roman number of series} is passed to \@hybridseriesname to convert it into the human-readable name.
% The second part {arabic number of hybrid} is used as is.
%
\newcommand{\@hyb}[2]{%
H^{\@hybridseriesname{#1}}_{#2}%
}
%
% \hyb takes a the designation of a label and expands to "H^{human-readable series name}_{hybrid counter}.
% \hyb is supposed to be used in math mode.
%
\newcommand{\hyb}[1]{%
\@expand@hyb{\getrefnumber{#1}}%
}
%
% A helper macro in the spirit of \@expandtwoargs from the LaTeX2e sources
%
% #1 is a token that ultimately expands into two tokens
% {roman number of series}{arabic numer of hybrid}
%
% This macro first expands #1 and then lets \@hyb process the expanded #1
%
\def\@expand@hyb#1{%
\edef\reserved@hyb{\noexpand\@hyb #1}%
\reserved@hyb%
}
%
% This theorem style is mostly equivalent to the plain style.
% But the counter (##2) is passed to \@hyb such that is nicely printed as
% "H^{human-readable series name}_{hybrid counter}"
% and not as
% {roman number of series}{arabic numer of hybrid}
%
% ##1 Printable name (e.g. Theorem, Lemma, etc.); here this always equals "Hybrid"
% ##2 Printable and internally formatted counter value, i.e. {roman number of series}{arabic numer of hybrid}
% ##3 Optional decription
\newtheoremstyle{@hybridstyle}{%
\item[\hskip\labelsep \theorem@headerfont ##1\ $\@expand@hyb{##2}$\theorem@separator]%
}{%
\item[\hskip\labelsep \theorem@headerfont ##1\ $\@expand@hyb{##2}$\ (##3)\theorem@separator]%
}
%
% Defines the hybrid-enviroment
% Uses the special @hybridstyle, make the counter \c@hybrid subordinate to \c@hybridseries and formats \c@hybrid as
% {roman number of series}{arabic numer of hybrid}
%
\theoremstyle{@hybridstyle}
\theoremheaderfont{\normalfont\bfseries}
\theoremseparator{}
\theorembodyfont{\normalfont\itshape}
\theoremsymbol{}
\newtheorem{hybrid}{Hybrid}[hybridseries]
\renewcommand{\thehybrid}{{\thehybridseries}{\number\c@hybrid}}
%
% Defines name and label format for cleveref.
% Again, the formatted counter #1 is passed to \@hyb such that is nicely printed as
% "H^{human-readable series name}_{hybrid counter}"
% and not as
% {roman number of series}{arabic numer of hybrid}
%
\crefname{hybrid}{hybrid}{hybrids}
\Crefname{hybrid}{Hybrid}{Hybrids}
\creflabelformat{hybrid}{#2$\@expand@hyb{#1}$#3}
\makeatother
\begin{document}
To prove security, we define a sequence of hybrids first.
\newhybridseries{\mathrm{security}}
\begin{hybrid}[Foo]\label{hyb:sec-foo}
This \namecref{hyb:sec-foo} modifies \ldots
\end{hybrid}
\begin{hybrid}[Bar]\label{hyb:sec-bar}
Didel di dum
\end{hybrid}
We now show the indistinguishability of these hybrids, i.e. we show that
% TODO: Does not work.
\begin{equation}
\hyb{hyb:sec-foo} \equiv \hyb{hyb:sec-bar}
\end{equation}
holds.
Privacy is also proven by a sequence of hybrds.
\newhybridseries{\mathrm{privacy}}
\begin{hybrid}[Foobar]\label{hyb:priv-foobar}
As in \cref{hyb:sec-foo}, this \namecref{hyb:priv-foobar} also \ldots
\end{hybrid}
\begin{hybrid}[Foo]\label{hyb:priv-foo}
Didel di dum
\end{hybrid}
\begin{table}[hbtp]\centering%
\begin{tabular}{l c c c}
Label & \texttt{ref} & \texttt{labelcref} & \texttt{cref} \\
\texttt{hyb:sec-foo} & \ref{hyb:sec-foo} & \labelcref{hyb:sec-foo} & \cref{hyb:sec-foo}\\
\texttt{hyb:sec-bar} & \ref{hyb:sec-bar} & \labelcref{hyb:sec-bar} & \cref{hyb:sec-bar}\\
\texttt{hyb:priv-foobar} & \ref{hyb:priv-foobar} & \labelcref{hyb:priv-foobar} & \cref{hyb:priv-foobar}\\
\texttt{hyb:priv-foo} & \ref{hyb:priv-foo} & \labelcref{hyb:priv-foo} & \cref{hyb:priv-foo}
\end{tabular}%
\caption{Test of References and Labels}%
\end{table}
\end{document}
答案3
在编写辅助文件时,使用用于显示计数器格式化值的宏来抑制扩展可能就足够了。
在下面的例子中,这是通过根据 定义事物来完成的\protected\def
。(由于某些不为人知的原因,当将 thm 文件的条目写入 aux 文件\DeclareRobustCommand
时,不起作用。)\@writefile
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[utf8]{inputenc}
\usepackage[hyperref]{ntheorem}
\theoremlisttype{allname}
\usepackage[unicode,final]{hyperref}
\usepackage{cleveref}
\input{glyphtounicode}
\pdfgentounicode=1
%
% How the hybrid mechanism works
%
% Hybrids are defined by a theorem-like environment call "hybrid" using the counter \c@hybrid.
% Hybrids can be grouped into series.
% To make the reference unique, series are also counted using \c@hybridseries.
% Each time \c@hybridseries is advanced, \c@hybrid is reset.
%
% Series have a human-readable name.
%
% A hybrid should be printed as "H^{human-readable series name}_{hybrid counter}".
% Also, the "public" API of ntheorem and cref use the printable form of the counters.
%
\makeatletter
% Counter for hybridseries
\newcounter{hybridseries}
\renewcommand{\thehybridseries}{\mathrmifmmode{\currenthybridseriesname}}
\@ifdefinable\mathrmifmmode{%
\protected\def\mathrmifmmode{\csname\texorpdfstring{\ifmmode mathrm\else @firstofone\fi}{@firstofone}\endcsname}%
}%
\newcommand{\newhybridseries}[1]{%
\@bsphack\stepcounter{hybridseries}\setcounter{hybrid}{-1}\gdef\currenthybridseriesname{#1}\@esphack
}
% This theorem style is mostly equivalent to the plain style.
%
% ##1 Printable name (e.g. Theorem, Lemma, etc.); here this always equals "Hybrid"
% ##2 Printable and internally formatted counter value, i.e. {roman number of series}{arabic numer of hybrid}
% ##3 Optional decription
\newtheoremstyle{@hybridstyle}{%
\item[\hskip\labelsep \theorem@headerfont ##1\ ##2\theorem@separator]%
}{%
\item[\hskip\labelsep \theorem@headerfont ##1\ ##2\ (##3)\theorem@separator]%
}
\theoremstyle{@hybridstyle}
\theoremheaderfont{\normalfont\bfseries}
\theoremseparator{}
\theorembodyfont{\normalfont\itshape}
\theoremsymbol{}
\newtheorem{hybrid}{Hybrid}[hybridseries]
\renewcommand{\thehybrid}{\thehybridformatting{\thehybridseries}{\arabic{hybrid}}}%
\@ifdefinable\thehybridformatting{%
\protected\def\thehybridformatting#1#2{%
\texorpdfstring{\ifmmode H^{#1}_{#2}\else $H^{#1}_{#2}$\fi}{H\string^\string{#1\string}\string_\string{#2\string}}%
}%
}%
\crefname{hybrid}{hybrid}{hybrids}
\Crefname{hybrid}{Hybrid}{Hybrids}
\creflabelformat{hybrid}{#2#1#3}
\def\l@hybridcopy{\thm@thmline}
\newcommand\myl@hybrid[3]{\l@@hybrid#1{#2}{#3}}
\newcommand\l@@hybrid[5]{%
\ifx\\#5\\%
\@dottedtocline{-2}{0em}{3.8em}{#1 \protect\numberline{#2}#3}{#4}%
\else
\ifHy@linktocpage\relax
\relax
\@dottedtocline{-2}{0em}{3.8em}{#1 \protect\numberline{#2}#3}{\hyper@linkstart{link}{#5}{#4}\hyper@linkend}%
\else
\@dottedtocline{-2}{0em}{3.8em}{\hyper@linkstart{link}{#5}{#1 \protect\numberline{#2}#3}\hyper@linkend}{#4}%
\fi
\fi
}%
\newcommand\switchlattheorem{\ifx\l@hybridcopy\l@hybrid\let\l@hybrid=\myl@hybrid\fi}
\addtocontents{thm}{\string\switchlattheorem}
\makeatother
\begin{document}
\section*{List of hybrids}
\listtheorems{hybrid}
\bigskip\hrule\bigskip
To prove security, we define a sequence of hybrids first.
\newhybridseries{security}
\begin{hybrid}[Foo]\label{hyb:sec-foo}
This \namecref{hyb:sec-foo} modifies \ldots
\end{hybrid}
\begin{hybrid}[Bar]\label{hyb:sec-bar}
Didel di dum
\end{hybrid}
We now show the indistinguishability of these hybrids, i.e. we show that
% TODO: Does not work.
\begin{equation}
\ref*{hyb:sec-foo} \equiv \ref*{hyb:sec-bar}
\end{equation}
holds.
Privacy is also proven by a sequence of hybrds.
\newhybridseries{privacy}
\begin{hybrid}[Foobar]\label{hyb:priv-foobar}
As in \cref{hyb:sec-foo}, this \namecref{hyb:priv-foobar} also \ldots
\end{hybrid}
\begin{hybrid}[Foo]\label{hyb:priv-foo}
Didel di dum
\end{hybrid}
\begin{table}[hbtp]\centering%
\begin{tabular}{l c c c}
Label & \texttt{ref} & \texttt{labelcref} & \texttt{cref} \\
\texttt{hyb:sec-foo} & \ref{hyb:sec-foo} & \labelcref{hyb:sec-foo} & \cref{hyb:sec-foo}\\
\texttt{hyb:sec-bar} & \ref{hyb:sec-bar} & \labelcref{hyb:sec-bar} & \cref{hyb:sec-bar}\\
\texttt{hyb:priv-foobar} & \ref{hyb:priv-foobar} & \labelcref{hyb:priv-foobar} & \cref{hyb:priv-foobar}\\
\texttt{hyb:priv-foo} & \ref{hyb:priv-foo} & \labelcref{hyb:priv-foo} & \cref{hyb:priv-foo}
\end{tabular}%
\caption{Test of References and Labels}%
\end{table}
\end{document}