带有子文件的正确参考编号

带有子文件的正确参考编号

考虑将以下 mwe 分为 3 个文件:

主要.tex:

\documentclass[12pt]{report}

\usepackage{subfiles}
\newcommand{\onlyinsubfile}[1]{#1}
\newcommand{\notinsubfile}[1]{}

\usepackage{amsmath}

\begin{document}

\renewcommand{\onlyinsubfile}[1]{}
\renewcommand{\notinsubfile}[1]{#1}

main:

\begin{equation}\label{eqn:main}
    1+1=2
\end{equation}

\subfile{subfile1}

\end{document}

子文件1.tex:

\documentclass[main.tex]{subfiles}

\onlyinsubfile{
    \usepackage{amsmath}
    \usepackage{xr}
    \externaldocument{main}
}

\begin{document}

Subfile1 

\begin{equation}
\label{eqn:a}
    a= b+c
\end{equation}

1: main ref: \ref{eqn:main}

\renewcommand{\onlyinsubfile}[1]{}
\renewcommand{\notinsubfile}[1]{#1}
\subfile{subfile2}

\end{document}

子文件2.tex:

\documentclass[main.tex]{subfiles}

\onlyinsubfile{
    \usepackage{amsmath}
    \usepackage{xr}

    \externaldocument{main} 
    \externaldocument{subfile1} 
}

\begin{document}

2: subfile ref: \ref{eqn:a}

2: main ref \ref{eqn:main}

\end{document}

如果我排版 main.tex 我会得到(正如预期的那样)

主页.pdf

问题是,如果我单独编译 subfile1.tex (或 subfile2.tex),参考编号会发生冲突,并会得到以下结果:

子文件1.pdf:

子文件1

子文件2.pdf:

子文件2

有没有办法获得正确的编号?在我的示例中,我只有几个方程式,但通常我可能有定理、定义和其他环境,因此在每个子文件的开头“手动”初始化每个计数器可能会非常繁琐。

答案1

您希望在编译 main.tex 得到的 pdf 文件和编译 subfile1.tex / subfile2.tex 得到的 pdf 文件中使用相同的编号吗?

如果是这样,则需要在编译 subfile1.tex / subfile2.tex 时将计数器的值初始化为编译 main.tex 时这些计数器所具有的值。

解决方案 1:

为此,您可以放置​​标签并结合使用 xr-package 和 Heiko Oberdiek 的 refcount-package。

您可能还希望有一种机制来检查所讨论的参考文献是否可以在同一文档中找到或者是否可以在外部 main.pdf 中找到。

当不使用 xr 包而是使用 hyperref 包和 xr-hyper 包时,这可能特别有用,因为在这种情况下,您需要决定引用创建的超链接是否必须指向同一个文档或外部 main.pdf。

在下面的例子中,该机制由以下部分组成\localorexternallabel:此宏作为参数采用标签的名称。如果定义了标签,则将使用该标签名称。如果未定义,则来自宏的短语\labelprefix将添加到标签名称的前面,这意味着从外部(主)文档引用标签。

主文本

\documentclass[12pt]{report}
\usepackage{amsmath}
%%%%%
% Either:
%\usepackage{xr-hyper}
%\usepackage{hyperref}
% Or:
\usepackage{xr}
%%%%% 
\usepackage{refcount}
\usepackage{subfiles}
\newcommand{\onlyinsubfile}[1]{#1}
\newcommand{\notinsubfile}[1]{}
\newcommand\labelprefix{}
\newcommand\localorexternallabel[1]{%
  \expandafter\ifx\csname r@#1\endcsname\relax
    \labelprefix
  \fi #1%
}


\begin{document}

\renewcommand{\onlyinsubfile}[1]{}
\renewcommand{\notinsubfile}[1]{#1}

main:

\begin{equation}\label{eqn:main}
    1+1=2
\end{equation}

\subfile{subfile1}

\end{document}

子文件1.tex

\documentclass[main.tex]{subfiles}

\onlyinsubfile{%
    \csname @ifpackageloaded\endcsname{xr-hyper}{%
      \externaldocument[MAIN]{main}[main.pdf]% xr-hyper in use; optional argument for url of main.pdf for hyperlinks
    }{%
      \externaldocument[MAIN]{main}% xr in use
    }%
    \renewcommand\labelprefix{MAIN}%
    % Initialize the counters via the labels belonging to the main document:
    \setcounter{equation}{\numexpr\getrefnumber{\labelprefix eqn:a}-1\relax}%
}

\begin{document}

Subfile1 

\begin{equation}
\label{eqn:a}
    a= b+c
\end{equation}

1: main ref: \ref{\localorexternallabel{eqn:main}}

\renewcommand{\onlyinsubfile}[1]{}
\renewcommand{\notinsubfile}[1]{#1}
\subfile{subfile2}

\end{document}

子文件2.tex

\documentclass[main.tex]{subfiles}

\onlyinsubfile{%
    \csname @ifpackageloaded\endcsname{xr-hyper}{%
      \externaldocument[MAIN]{main}[main.pdf]% xr-hyper in use; optional argument for url of main.pdf for hyperlinks
    }{%
      \externaldocument[MAIN]{main}% xr in use
    }%
    \renewcommand\labelprefix{MAIN}%
    % Initialize the counters via the labels belonging to the main document:
    % - no counters used -
}

\begin{document}

2: subfile ref: \ref{\localorexternallabel{eqn:a}}

2: main ref \ref{\localorexternallabel{eqn:main}}

\end{document}

主页.pdf

在此处输入图片描述

子文件1.pdf

在此处输入图片描述

子文件2.pdf

在此处输入图片描述

\includeonly顺便说一句:您可能对LaTeX 2e 内核的功能感兴趣。



解决方案 2:

当编译 subfile1.tex / subfile2.tex 时,您需要将计数器的值初始化为编译 main.tex 时这些计数器所具有的值。

为此,你可以借用 LaTeX 2e 内核的代码 - \include-\includeonly机制来写入所有柜台通过定义\newcounter为引用标签,该标签被滥用来执行许多调用,\setcounter而不仅仅是传递一些数字。

我建议滥用引用标签,因为引用标签可以通过\externaldocument子文件导入。

我使用宏执行了此操作\MoveCountersToOrFromLabel

在编译时使用主文本它将把\setcounter所有计数器值的调用作为单个引用标签写入 .aux 文件。

当编译子文件时使用它,它将从 main.aux 相应的外部标签中检索计数器值。

由于计数器值的集合是通过引用标签保存的,因此引用标签需要有一个名称。该名称就是 的参数\MoveCountersToOrFromLabel

除此之外:

除了宏\onlyinsubfile/之外\notinsubfile,您还可以在序言中使用\@ifclassloaded分叉,具体取决于 documentclass子文件也已加载,但在编译时则不会出现这种情况主文本

主文本

\documentclass[12pt]{report}
\usepackage{amsmath}

% Either:
\usepackage{xr-hyper}
\usepackage{hyperref}
% Or:
%\usepackage{xr}

\makeatletter
\@ifundefined{@car}{\newcommand\@car{}\long\def\@car#1#2\@nil{#1}}{}%
\newcommand\setdefinedcounter[2]{%
  \@ifundefined{c@#1}{\newcounter{#1}}{}%
  \setcounter{#1}{#2}%
}%
\@ifclassloaded{subfiles}{%
  % Obviously we are in a sub-file as only sub-files load the subfile-class.
  \@ifpackageloaded{xr-hyper}{%
    \externaldocument[MAIN]{main}[main.pdf]% xr-hyper in use; optional argument for url of main.pdf for hyperlinks
  }{%
    \externaldocument[MAIN]{main}% xr in use
  }%
  \newcommand\labelprefix{MAIN}%
  %    Define \MoveCountersToOrFromLabel to extract the referencing-label holding the
  %    counter-values. This label is imported from main.tex/main.aux, thus \labelprefix
  %    is needed. The macro underlying that label is \r@\labelprefix<label-name> and
  %    we need the first undelimited argument of its expansion. This we grab via \@car.
  \newcommand\MoveCountersToOrFromLabel[1]{%
    \@bsphack
    % There are counters like section@level that get defined via
    % some hook (like \AtBeginDocument) after the preamble, thus
    % check if still in preamble, and if so, apply the hook, too:
    \ifx\@onlypreamble\@notprerr
      \expandafter\@firstoftwo
    \else
       \expandafter\@secondoftwo
    \fi{\@firstofone}{\AtBeginDocument}%
    {%
      \@ifundefined{r@\labelprefix#1}{}{%
        \expandafter\expandafter\expandafter\@car\csname r@\labelprefix#1\endcsname\@nil
      }%
    }%
    \@esphack
  }%
}{%
  % Obviously we are in the main document as the main document does not load the subfile-class.
  \newcommand\labelprefix{}%
  %    Define \MoveCountersToOrFromLabel to write counter-values to referencing-label:
  \newcommand\MoveCountersToOrFromLabel[1]{%
    \@bsphack
    \if@filesw 
      \protected@write\@auxout{%
        \let\savedwrite\write
        \def\write{\immediate\savedwrite}%
        \def\@elt##1{%
          \string\protect
          \string\setdefinedcounter{##1}{\the\@nameuse{c@##1}}\@percentchar^^J%
        }%
      }{%
        \string\newlabel{#1}{{\@percentchar^^J\cl@@ckpt}{}{}{}{}}%
      }%
    \fi
    \@esphack
  }%
}%
% Check whether the label in question is available in the current document or whether it
% needs to be retrieved from the external main.pdf/main.aux:
\newcommand\localorexternallabel[1]{%
  \expandafter\ifx\csname r@#1\endcsname\relax
    \labelprefix
  \fi#1%
}%
\makeatother

\usepackage{subfiles}

\begin{document}

main:

\begin{equation}\label{eqn:main}
    1+1=2
\end{equation}

\subfile{subfile1}

\end{document}

子文件1.tex

\documentclass[main.tex]{subfiles}
\MoveCountersToOrFromLabel{subfile1}
\begin{document}

Subfile1 

\begin{equation}
\label{eqn:a}
    a= b+c
\end{equation}

1: main ref: \ref{\localorexternallabel{eqn:main}}

\subfile{subfile2}

\end{document}

子文件2.tex

\documentclass[main.tex]{subfiles}
\MoveCountersToOrFromLabel{subfile2}
\begin{document}

2: subfile ref: \ref{\localorexternallabel{eqn:a}}

2: main ref \ref{\localorexternallabel{eqn:main}}

\end{document}

主页.pdf

在此处输入图片描述

子文件1.pdf

在此处输入图片描述

子文件2.pdf

在此处输入图片描述

相关内容