制作有序附录

制作有序附录

我正在尝试做到这一点,以便可以在文档主体的任何时候包含成为附件一部分的参考资料。

我大致基于此:自动排序附录

\newcounter{annexes}
\newcommand{\annexRef}[1]{\hyperref[#1]{annex~\ref*{#1}} %
\stepcounter{annexes}%
\expandafter\xdef\csname annexpath.\arabic{annexes}\endcsname{#1}%
}

\newcommand{\printAnnexes}{
    \appendix
    \setcounter{secnumdepth}{0}
    \begin{appendices}
        \count1=0
        \loop\ifnum\count1 < \value{annexes}\relax
            \advance\count1 by 1\relax
            {
            \count2=1 \relax
            \count3=0 \relax
            \loop\ifnum\count2 < \count1 \relax
                \expandafter\ifx\csname annexpath.\number\count1\endcsname = \csname annexpath.\number\count2\endcsname
                    \advance\count3 by 1 \relax
                \fi
                \advance\count2 by 1 \relax
            \repeat
            \ifnum\count3 < 1 \relax
                \input{\csname annexpath.\number\count1\endcsname}
            \fi
            }
        \repeat
    \end{appendices}
}

因此,我可以在文档的任何位置书写\annexRef{path/to/file.latex},它会创建参考并将其包含在附件部分。

目前它可以正确输入附件文件,但是内循环和后续循环\ifnum应该使文件仅输入一次。也就是说,如果同一个文件被引用两次,则当前正在输入两次,我只希望它被输入一次。

提前感谢你的帮助

答案1

expl3并不难。这个想法是按顺序存储引用列表,但前提是该项目尚未进入。

最后我们可以映射序列并创建附录。

这里我使用filecontents\jobname只是为了使示例独立。

\begin{filecontents}{\jobname-annex-1}
This is annex 1
\end{filecontents}
\begin{filecontents}{\jobname-annex-2}
This is annex 2
\end{filecontents}
\begin{filecontents}{\jobname-annex-3}
This is annex 3
\end{filecontents}

\documentclass{article}
\usepackage{hyperref}

\ExplSyntaxOn

\NewDocumentCommand{\annexRef}{m}
 {
  \joanthan_annex_ref:n { #1 }
 }

\NewDocumentCommand{\printAnnexes}{}
 {
  \joanthan_annex_print:
 }

\seq_new:N \g_joanthan_annex_list_seq

\cs_new_protected:Nn \joanthan_annex_ref:n
 {
  \hyperref[#1]{annex\nobreakspace\ref*{#1}}
  \seq_if_in:NnF \g_joanthan_annex_list_seq { #1 }
   {
    \seq_gput_right:Nn \g_joanthan_annex_list_seq { #1 }
   }
 }

\cs_new_protected:Nn \joanthan_annex_print:
 {
  \appendix
  \seq_map_inline:Nn \g_joanthan_annex_list_seq
   {
    \section{Annex~\ref*{##1}\label{##1}}
    \input{##1}
   }
 }

\ExplSyntaxOff

\begin{document}

\section{First}

Some text \annexRef{\jobname-annex-1}

Some text \annexRef{\jobname-annex-3}

\section{Second}

Some text \annexRef{\jobname-annex-1}

Some text \annexRef{\jobname-annex-2}

\printAnnexes

\end{document}

在此处输入图片描述

答案2

为了使原始代码正常工作,请用以下代码替换外循环:

\count1=0
\loop\ifnum\count1 < \value{annexes}\relax
    \advance\count1 by 1\relax
    % only input the annex if it is known
    \ifcsname we have already seen \csname annexpath.\the\count1\endcsname\endcsname
    \else \input{\csname annexpath.\the\count1\endcsname}\fi
    % the line below leaves the csname defined (and equivalent to \relax)
    \csname we have already seen \csname annexpath.\the\count1\endcsname\endcsname
\repeat

原因和方法如下:

  • 涉及计数器的 TeX 编程既笨拙又冗长,难以阅读和编写。因此,虽然在其他编程语言中,数字变量可能是您首先想到的东西,但在 TeX 中,您应该尽量避免使用它们。
  • 另一方面,定义宏是一种非常出色且惯用的工具。实际上,宏定义可以为您提供关联数组 - 也许您确实应该将宏视为数组而不是过程。
    • 正如您所知,任何字符都可以通过 成为宏名称的一部分\csname ... \endcsname
    • \ifdefined可以使用或 来测试宏是否存在\ifcsname ... \endcsname
    • 一个简单的\csname ... \endcsname语句将赋予不存在的宏以含义\relax
  • 因此,如果您只是为已经读取的每个文件定义一个宏(即:将其文件名作为键添加到数组中we have already seen),则您只需要在读取之前检查它在该数组中的存在(即:作为宏存在)。

事实上,您可以进一步简化代码,根本不使用计数器:

\newtoks\annexToks
\def\annexRef#1{%
    % store the file names in a list
    \global\annexToks =
        \expandafter{\the\annexToks{#1}}%
    \hyperref[#1]{annex-\ref*{#1}}}

\def\printAnnexes{%
    \appendix
    % terminate the list with the command that iterates over the list
    \expandafter\doPrintAnnexes
        \the\annexToks{\doPrintAnnexes}}
\def\doPrintAnnexes#1{%
    \ifx\doPrintAnnexes#1
        \expandafter\gobble % eats the continuing \doPrintAnnexes
    \else
        \ifcsname we have seen #1\endcsname
        \else
            \section {Annex #1}
            \label {#1}
            \input {#1}
        \fi
        \csname we have seen #1\endcsname
    \fi \doPrintAnnexes}

\def\gobble#1{} % you could also use \@gobble if the at is a letter

在这里,你将(可能)想要读取的文件存储在一个列表中,作为{}标记寄存器中被包围的组\annexToks。 with 的构造\doPrintAnnexes为你提供了循环遍历此类列表的最简单方法。

相关内容