定理和标签

定理和标签

在回答实际问题之前,让我先介绍一下背景知识。我查看了一下latex.ltx标签的处理方式。我发现:

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

定义\label为本质上\newlabel.aux文件写入命令。让我来解释一下。\protected@write如下:

\long\def \protected@write#1#2#3{%
      \begingroup
       \let\thepage\relax
       #2%
       \let\protect\@unexpandable@protect
       \edef\reserved@a{\write#1{#3}}%
       \reserved@a
      \endgroup
      \if@nobreak\ifvmode\nobreak\fi\fi
}

是一篇关于 的有趣读物\let\thepage\relax,可能也会证明分组的合理性。#2中为空,\label所以谁在乎呢。 的名称\@unexpandable@protect是不言自明的,正如\def\@unexpandable@protect{\noexpand\protect\noexpand}所证实的那样。 接下来是\@auxout,它是当前文件,即如果我们处于包含文件的中间,.aux则为\@mainaux或。 因此,我们了解了 的所有内容,除了和。\@partaux\label\@bsphack\@esphack解释一下。然后我发现在.aux我的一个文件中,我确实找到了:

\newlabel{thm:defi:SM}{{1.2.1.1}{2}{Spazio Metrico}{defi.1.2.1.1}{}}

\label我想知道为什么第二个括号对中有 5 个参数,而定义中只写两个参数,以及它们是如何使用的。所以我尝试阅读\ref

\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstoftwo{#1}}

顺便说一句,我发现与 保存\pageref相同的是而不是。是:\ref\@secondoftwo\@firstoftwo\@setref

\def\@setref#1#2#3{%
  \ifx#1\relax
   \protect\G@refundefinedtrue
   \nfss@text{\reset@font\bfseries ??}%
   \@latex@warning{Reference `#3' on page \thepage \space
             undefined}%
  \else
   \expandafter#2#1\null
  \fi}

如果标签未定义,则\csname r@#1\endcsname传递给\@setref\ref\relax,因此在这种情况下,我们会输出粗体??(带有一些我没有费心去解读的字体命令)和警告,否则我们会得到#2#1#2\@firstoftwo\@secondoftwo取决于是否\@setref\ref或调用\pageref#3是标签,并且仅在警告消息中使用。什么定义了\csname r@#1\endcsname?因为的其余部分\@setref\expandafter#2#1\null,并且\null只是一个空的\hbox,可能是为了避免不必要的交互而与后面的内容分开。所以我们进入\newlabel

\def\newlabel{\@newl@bel r}
\@onlypreamble\@newl@bel

\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}}}

假设警告被正确处理,就像 一样\@ifundefined,如果 已经定义,这应该发出警告r@#1,如果未定义,则不执行任何操作,无论如何都会这样做\@namedef,即:

\def\@namedef#1{\expandafter\def\csname #1\endcsname}

这是的定义\csname r@<label>\endcsname:它是的#3,它是#2\newlabel(或者更确切地说,是什么似乎在用户级别(或者更确切地说是用户级别)是。因此,这就是 中#2的内容。一开始是假的,然后在文档处理过程中被修改,因此跟踪其变化基本上是不可能的。然而,问题仍然存在:如何获取伪 中的 5 个括号对,为什么如果我们只有and而不是or 之类的东西,我在输出中看不到它们?答案在于,它是:\newlabel.aux{{\@currentlabel}{\thepage}}\csname r@<label>\endcsname\@currentlabel#2\newlabel\@firstoftwo\@secondoftwo\@firstoffivehyperref\let\ref

\def\HyPsd@ref#1{\HyPsd@@ref#1*\END}%
\def\HyPsd@@ref#1*#2\END{%
  \ifx\\#2\\%
    \HyPsd@@@ref{#1}%
  \else
    \expandafter\HyPsd@@@ref
  \fi
}%
\def\HyPsd@@@ref#1{%
  \expandafter\ifx\csname r@#1\endcsname\relax
    ??%
  \else
    \expandafter\expandafter\expandafter
    \@car\csname r@#1\endcsname\@nil
  \fi
}

顺便说一句,它对 做了类似的事情\pageref#2of\HyPsd@@ref作为空参数传递,在条件中给出 true 并使 LaTeX 执行\HyPsd@@@ref{#1},其中的#1参数是to。顺便说一句,每当发生上述情况时,就是to ,那么 是从哪里来的?也许吧?好吧,我们稍后再讲。假设 cs 的定义与之前相同,除了它具有上述方式中看到的所有 5 个括号对,我们看到如果 cs 未定义,则输出 ??,否则 cs 将由 s 生成并扩展为适当的数字,然后传递给\HyPsd@ref\ref\let\label\let\@gobble\let\csname r@<label>\endcsnamethmtools\newlabel\expandafter@car…\@nil,它的作用是\@firstoffive。替代方法\pageref可能使用\@cbr,它与 相同,只是\@car它需要第二个参数。所以现在我知道了如何在 pdf 字符串中处理参数,因为我看到\let上面描述的 s 发生在 中\pdfstringdef。定理是使用 pdf 字符串的示例,也是我真正感兴趣的东西,可能一直以来都是如此。我使用thmtools。所以现在的问题是:密钥label=到底有什么用?

总结一下,问题是:

  1. label=包中的 key到底起什么作用thmtools?它\label在内部使用吗?
  2. 那 5 个括号对是什么?它们似乎是{ctr sequence associated with the theorem}{page on which the theorem starts}{theorem name= key}{theorem ctr name.ctr sequence}{empty}。这是通用的吗?空括号对有什么用?
  3. 额外的 3 个“参数”如何使用?

更新: 再看另一个.aux,我注意到方程式的标签有类似的东西。我在顶部也看到了这个:

\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined
\global\let\oldcontentsline\contentsline
\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
\global\let\oldnewlabel\newlabel
\gdef\newlabel#1#2{\newlabelxx{#1}#2}
\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}

因此,在文档的开头,\newlabel本身被重新定义,使其吞噬了额外的“参数”。这使得问题变得更加紧迫:这些参数是用来做什么的?这也引出了一个新问题:为什么\newlabel重新定义\let为旧含义\AtEndDocument?在什么条件下会发生重新定义?那是什么\hyper@anchor?但也许我问的问题太多了。

答案1

让我们检查一份简单的文档。

\documentclass{article}
\usepackage{amsthm,thmtools}
\usepackage{hyperref}

\declaretheorem{theorem}

\begin{document}

\section{A section title}\label{sec-a}

\begin{theorem}[label=thm-e]
$0\ne1$
\end{theorem}

\begin{theorem}[name=Key theorem,label=thm-key]
$0=0$
\end{theorem}

\end{document}

在此处输入图片描述

\newlabel我们在文件中找到的条目.aux

\newlabel{sec-a}{{1}{1}{A section title}{section.1}{}}
\newlabel{thm-e}{{1}{1}{}{theorem.1}{}}
\newlabel{thm-key}{{2}{1}{Key theorem}{theorem.2}{}}

如果hyperref不使用,条目将会不同:

\newlabel{sec-a}{{1}{1}}
\newlabel{thm-e}{{1}{1}}
\newlabel{thm-key}{{2}{1}}

因此我们看到,这hyperref扩展了文件中写出的数据.aux。第二个参数\newlabel包含五个括号对:

  1. 计数器的值
  2. 页码
  3. 标题
  4. 超链接锚点\ref
  5. 空(为将来的扩展保留)

标题字段用于\nameref;当您name=...在 的可选参数中使用 时\begin{theorem},您也可以使用\nameref{thm-key},并且名称将被打印,就像\nameref{sec-a}

请注意,这thmtools没有什么特别的。输入

\documentclass{article}
\usepackage{amsthm}
\usepackage{hyperref}

\newtheorem{theorem}{Theorem}

\begin{document}

\section{A section title}\label{sec-a}

\begin{theorem}\label{thm-e}
$0\ne1$
\end{theorem}

\begin{theorem}[Key theorem]\label{thm-key}
$0=0$
\end{theorem}

\end{document}

文件中的注释.aux将是相同的:

\newlabel{sec-a}{{1}{1}{A section title}{section.1}{}}
\newlabel{thm-e}{{1}{1}{}{theorem.1}{}}
\newlabel{thm-key}{{2}{1}{Key theorem}{theorem.2}{}}

label=thm-e可选参数中的键在处理过程中被简单地翻译\label{thm-e}\begin{theorem}


代码

\providecommand\hyper@newdestlabel[2]{}
\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined
\global\let\oldcontentsline\contentsline
\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
\global\let\oldnewlabel\newlabel
\gdef\newlabel#1#2{\newlabelxx{#1}#2}
\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}
\AtEndDocument{\ifx\hyper@anchor\@undefined
\let\contentsline\oldcontentsline
\let\newlabel\oldnewlabel
\fi}
\fi}

.aux是针对使用 loaded 写入文件hyperref,然后在不使用 的情况下重新处理文件的情况的一种保护措施hyperref.aux在这种情况下,当在 begin document 处读取文件时,额外的参数会使 LaTeX 感到困惑,因此命令\newlabel被临时重新定义为执行它通常在不使用 时执行的操作hyperref,并且额外的参数会被吞掉。

阅读完.aux开始文档的文件后,LaTeX 重新打开该文件进行写入,从而生成一个新版本。

类似的治疗方法也适用于\contentsline

相关内容