修改标签定义

修改标签定义

我正在尝试修改\label命令,以便除了页面和之外,还将章节存储在 .aux 文件中\@currentlabel。我尝试了以下步骤,但没有效果。

\documentclass{book}
\usepackage{amsthm}
\makeatletter
\def\@newl@bel#1#2#3{%
    \@ifundefined{#1@#2}%
    \relax
    {\gdef \@multiplelabels {%
            \@latex@warning@no@line{There were multiply-defined labels}}%
        \@latex@warning@no@line{Label `#2' multiply defined}}%
    \global\@namedef{#1@#2}{#3}}
\def\newlabel{\@newl@bel r}
\@onlypreamble\@newl@bel
\let \@multiplelabels \relax
\def\label#1{\@bsphack
\protected@write\@auxout{}%
{\string\newlabel{#1}{{\@currentlabel}{\thepage}{\thechapter}}}%
\@esphack}
\def\refstepcounter#1{\stepcounter{#1}%
\protected@edef\@currentlabel
{\csname p@#1\endcsname\csname the#1\endcsname}%
}

\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstofthree{#1}}
\def\pageref#1{\expandafter\@setref\csname r@#1\endcsname\@secondofthree{#1}}
\def\chapref#1{\expandafter\@setref\csname r@#1\endcsname\@thirdofthree{#1}}
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\label{theo}abc\end{theorem}
Theorem \ref{theo} in chapter \chapref{theo}, page \pageref{theo} says that abc.
\end{document}

\chapref即使无法识别,新命令仍可正常工作,而\ref,和\pageref返回\@currentlabel \thepage和 的连接thechapter

我不太明白这些变量代表什么,\@newl@bel这让我很难看出我做错了什么。

正如我在评论中提到的,我对不需要任何参考包的解决方案感兴趣。我知道这个问题,但我想知道是否可以通过修改 \newlabel 来实现。

答案1

这很容易,zref并定义一个新chapterprop属性,然后存储\thechapter

然而要付出的代价\zref\zlabel\zpageref

\documentclass{book}
\usepackage{amsthm}
\usepackage[user]{zref}


\makeatletter
\zref@newprop{chapterprop}{\thechapter}
\zref@addprops{main}{chapterprop}
\newcommand{\chapref}[1]{\zref@extract{#1}{chapterprop}}%\expandafter\@setref\csname r@#1\endcsname\@thirdofthree{#1}}
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\zlabel{theo}abc\end{theorem}
Theorem \zref{theo} in chapter \chapref{theo}, page \zpageref{theo} says that abc.
\end{document}

更新无需任何*ref相关包,只需提供命令即可进行黑客\label攻击。\ref\pageref\@...ofthree

\documentclass{book}
\usepackage{amsthm}
\makeatletter

\def\label#1{\@bsphack
  \protected@write\@auxout{}%
  {\string\newlabel{#1}{{\@currentlabel}{\thepage}{\thechapter}}}%
  \@esphack}

\long\def\@firstofthree#1#2#3{#1}
\long\def\@secondofthree#1#2#3{#2}
%\long\def\@threeofthree#1#2#3{#3}% Is defined in `latex.ltx` already

\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstofthree{#1}}
\def\pageref#1{\expandafter\@setref\csname r@#1\endcsname
                                   \@secondofthree{#1}}
\def\chapref#1{\expandafter\@setref\csname r@#1\endcsname
                                   \@thirdofthree{#1}}
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\label{theo}abc\end{theorem}
Theorem \ref{theo} in chapter \chapref{theo}, page \pageref{theo} says that abc.
\end{document}

在此处输入图片描述

答案2

在注释掉一些不必要的内容并添加\@firstofthree和的定义后,您的代码似乎可以工作了\@secondofthree。(\@thirdoftree已定义。)

你的代码确实破坏了超链接-package,因此只有在超链接-package 未加载。

\documentclass{book}
\usepackage{amsthm}
\makeatletter
\renewcommand*\@newl@bel[3]{%
  \@ifundefined{#1@#2}%
  \relax
  {%
    \gdef\@multiplelabels{%
      \@latex@warning@no@line{There were multiply-defined labels}%
    }%
    \@latex@warning@no@line{Label `#2' multiply defined}%
  }%
  \global\@namedef{#1@#2}{#3}%
}%
%\@onlypreamble\@newl@bel
%\let\@multiplelabels\relax
\renewcommand*\label[1]{%
  \@bsphack
  \protected@write\@auxout
                  {}%
                  {\string\newlabel{#1}{{\@currentlabel}{\thepage}{\thechapter}}}%
  \@esphack
}%
%\def\refstepcounter#1{%
%  \stepcounter{#1}%
%  \protected@edef\@currentlabel
%  {\csname p@#1\endcsname\csname the#1\endcsname}%
%}%
\renewcommand*\ref[1]{%
  \expandafter\@setref\csname r@#1\endcsname\@firstofthree{#1}%
}%
\renewcommand*\pageref[1]{%
  \expandafter\@setref\csname r@#1\endcsname\@secondofthree{#1}%
}%
\newcommand*\chapref[1]{%
  \expandafter\@setref\csname r@#1\endcsname\@thirdofthree{#1}%
}
\newcommand\@firstofthree[3]{#1}%
\newcommand\@secondofthree[3]{#2}%
%\newcommand\@thirdofthree[3]{#3}%
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\label{theo}abc\end{theorem}
Theorem \ref{theo} in chapter \chapref{theo}, page \pageref{theo} says that abc.
\end{document}

如果你真的不想使用参考值-package 我可以提供另一个粗略的 hack,它似乎不会破坏超链接-包裹:

重新定义/修补\label-command,以便让\label-command 修补\@currentlabel-macro,使其\@currentlabel扩展为两个参数,前面有一个健壮的命令来选择两个参数之一,第一个参数保存\@currentlabel修补前的内容,第二个参数保存\thechapter

\documentclass{book}
\usepackage{amsthm}
%%\usepackage{hyperref}
\makeatletter
\DeclareRobustCommand\My@GetRefArg[2]{#1}%
\DeclareRobustCommand\MyOther@GetRefArg[2]{#2}%
\newcommand\My@saved@currentlabel{}%
\AtBeginDocument{%
  \let\My@oldlabel=\label
  \renewcommand\label[1]{%
    \@bsphack
    \let\My@saved@currentlabel=\@currentlabel
    \expandafter\def
    \expandafter\@currentlabel
    \expandafter{%
    \expandafter\My@GetRefArg
    \expandafter{%
    \@currentlabel}{\thechapter}}%
    \@esphack
    \My@oldlabel{#1}%
    \@bsphack
    \let\@currentlabel=\My@saved@currentlabel
    \@esphack
  }%
  \@ifpackageloaded{hyperref}{%
    \DeclareRobustCommand\chaprefAtNoStar[1]{%
      \begingroup
      \let\My@GetRefArg\MyOther@GetRefArg
      \ref{#1}%
      \endgroup
    }%
    \DeclareRobustCommand\chaprefAtStar[1]{%
      \begingroup
      \let\My@GetRefArg\MyOther@GetRefArg
      \ref*{#1}%
      \endgroup
    }%
    \DeclareRobustCommand\chapref{%
      \@ifstar\chaprefAtStar\chaprefAtNoStar
    }%
  }{%
    \DeclareRobustCommand\chapref[1]{%
      \begingroup
      \let\My@GetRefArg\MyOther@GetRefArg
      \ref{#1}%
      \endgroup
    }%
  }%
}%
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\label{theo}abc\end{theorem}
Theorem \ref{theo} in chapter \chapref{theo}, page \pageref{theo} says that abc.
%%
%%Theorem \ref*{theo} in chapter \chapref*{theo}, page \pageref*{theo} says that abc.
\end{document}

如果使用超链接,带有 的超链接\chapref不会指向相关章节的开头,而是指向在放置相应 之前放置的最后一个锚点\label。因此,在上面的例子中,带有 的超链接\chapref{theo}将转到相关定理的开头,尽管显示了该定理出现的章节编号。

如果使用超链接,您已“加星标”变体\ref\pageref显示相关数字,但不生成超链接。因此,在超链接正在加载的还有一个“加星标”的变体\chapref

!!!我不知道这些粗糙的黑客行为是否会破坏任何文档类或包的功能。!!!

!!!因此我不提供任何担保。如果有东西损坏,处理零件由您自己决定。!!!

!!!由于担心破坏任何文档类或包的功能,我强烈建议使用 zref-package。!!!

相关内容