知道它位于某个部分末尾的宏?

知道它位于某个部分末尾的宏?

在 LaTeX 中使用 \begin{section} ... \end{section} 是不是一个坏主意?Jan Hlavacek 说:

当然,通常可以识别某个部分的结束,但实际上部分结束的方式有很多种:另一部分的开始、下一章或下一部分的开始、\endmatter参考书目、索引等的开始、或文档的结束。

我该如何编写一个宏来识别何时到达某个部分的末尾?

我希望它能正常工作\afterpage这样我就可以修复一些问题我的答案每页顶部都有章节提醒吗? 我相信这意味着它必须使用标记来检测它相对于分段命令的位置,但我对 LaTeX 了解不够多,无法确定。

例如,我希望能够做如下的事情:

\documentclass{article}
\usepackage{afterpage}
\newcommand{\printendedsections}{%
    \ifatendofsubsubsection{(end of subsubsection \thesubsubsection)}{}%
    \ifatendofsubsection{(end of subsection \thesubsection)}{}%
    \ifatendofsection{(end of section \thesection)}{}%
    \ifatendofchapter{(end of chapter \thechapter)}{}%
    \ifatendofpart{(end of part \thepart)}{}%
}
\begin{document}

% will expand to '(end of subsection 2.1)' at the top of page 2 because
% subsection 2.2 starts right at the top of page 2
\afterpage{\hbox{\printendedsections}}

\section{sec1}

asdf
\printendedsections% expands to nothing because section 1 hasn't ended yet

\subsection{sub1.1}

\printendedsections% expands to nothing because subsection 1.1 hasn't ended yet
asdf
\printendedsections% expands to '(end of subsection 1.1)(end of section 1)'

\section{sec2}

asdf
\printendedsections% expands to nothing because section 2 hasn't ended yet

\subsection{sub2.1}

pretend there is enough content here
to push the start of subsection 2.2
to the top of the next page
\printendedsections% expands to '(end of subsection 2.1)'

\subsection{sub2.2}

asdf
\printendedsections% expands to '(end of subsection 2.2)(end of section 2)'

\end{document}

答案1

根据要求,问题无法解决(输入与示例类似)。TeX 是按顺序工作的,当它\printendedsections在运行文本中执行时,TeX 无法知道接下来出现的内容是更多文本、一些标题还是...

即使采用多通道解决方案,也几乎不可能确定,至少如果您不另外修改航向命令的话,因为需要确定\printendedsections和下一个航向命令之间有什么(如果有的话)。

暂时忽略确定某个部分是否从页面顶部开始的额外请求,当某个部分级别结束时自动输出文本的问题可以通过多种方式实现。下面是一种可以自动完成所有操作的方法:

\documentclass{article}

\usepackage{etoolbox}

\makeatletter
\patchcmd\@startsection%
    { \par}{\par \outputsectionends{#2}}%
    {\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}

\def\perhapssomethingended #1{%
        \ifnum \arabic{#1}>\z@
           (end of #1 \csname the#1\endcsname)%
       \fi
}
\makeatother

\def\outputsectionends #1{%
   \ifcase #1\relax
% extend here (+ \chapter command) for report/book class
   \or
      \perhapssomethingended{subsubsection}
      \perhapssomethingended{subsection}
      \perhapssomethingended{section}
      \setcounter{subsubsection}{0}         % need to reset high-level headings as LaTeX is lazy and only resets the next level
  \or
      \perhapssomethingended{subsubsection}
      \perhapssomethingended{subsection}
  \or
      \perhapssomethingended{subsubsection}
 \fi
\par
}

\AtEndDocument{\outputsectionends1}

\begin{document}
\section{sec1} asdf
\subsection{sub1.1}    asdf
\subsection{sub1.2}    asdf
\subsubsection{sub1.2.1}    asdf
\paragraph{sub1.2.1.1}    this level is not taken into account  (but could of course)
\paragraph{sub1.2.1.2}    this level is not taken into account 
\section{sec2} asdf
\subsection{sub2.1}
\subsection{sub2.2} asdf

\end{document}

解释:

我们连接到\@startsection生成标题(除章节外)的标准 LaTeX 接口。我们知道,如果调用此命令,#2则会生成带有“级别编号”的标题(章节为 1,子章节为 2 ...)。

因此,我们根据数字执行不同的操作:如果我们开始一个部分 (1),那么我们可能已经结束了一个“小部分”,也许结束了一个“小节”,也许结束了一个前一个“部分”。所以我们\perhapssomethingended对每个部分都运行。此命令查看当前计数器的值(作为其参数给出),例如“小节”,如果该值大于零,则存在前一个标题。因此我们输出一些文本。

只有一个问题:LaTeX 很懒,当它开始一个新标题时,它只会将下一个标题级别重置为零,而不会将所有更高的标题级别重置为零(因为这稍后会以递归方式发生)。然而,对我们来说这是一个问题,因为这意味着在“子部分 1.2.1”之后,它的值将保持在 1,从而在处理“子部分 2.1”时弄乱输出。因此,我们必须明确确保在处理一个部分时重置子部分计数器(您可以通过注释掉该\setcounter行来尝试)。

最后,我们还需要在文档末尾结束所有内容。这是通过假装这个地方像另一个部分一样运行来实现的,即我们\outputsectionends{1}在那里运行。

如果你运行这个你将得到:

在此处输入图片描述

当然,还有几个可能的改进,例如,如何格式化生成的文本(现在只是一个带有缩进的段落)。

检测页面顶部的部分

显然这行不通,\afterpage因为这一切都发生在幕后。然而,afterpage 无论如何都不是合适的工具,因为它在主样稿处理完毕后以异步方式插入某些内容,这不会有帮助。

我使用的方法是,在标题添加的断点前后添加标签。因此,如果两者最终都在同一页上,则此时没有发生中断;如果它们最终位于不同的页面上,则中断直接发生在标题前面。在这种情况下,\outputsectionends可以根据需要更改其行为(显然,在文档稳定之前,这会导致多次运行,特别是如果生成的文本量根据情况发生很大变化)。但我不太确定 OP 想要什么,所以我不会详细说明。

为部分或章节提供此解决方案

在评论中,有人问这个解决方案是否也有效\part\chapter答案是肯定的,也是否定的。上面的代码不是现成的。它需要以两种方式扩展代码

  1. \chapter\part通常不使用 来定义\@startsection。因此,它们的代码需要以类似的方式进行修补,以便在它们生成标题(以及可能的分页符等)之前运行\outputsectionends
  2. 此外,还\outputsectionends需要进行更改:的层次结构级别为\chapter0,的层次结构级别为\part-1。因此,\ifcase可以扩展以适应章节(代码中已经有注释说明操作的放置位置),但对于\part需要额外测试#1是否为 -1,如果\ifcase仅运行 0、1、2、...

更新

在评论中,有人问我在断点前后添加标签是什么意思。\@startsection用于生成可能断点的是:

 \addpenalty\@secpenalty\addvspace\@tempskipa

\addpenalty和命令\addvspace有点棘手,因此我们不能简单地在前后添加标签。为什么?因为它们会向后查看以检测前面是否有垂直空间,如果有,则将空间移到惩罚之后或将其与额外请求的空间相结合(在 的情况下\addvspace)。因此,如果我们在它前面放一个标签,\addpenalty意味着任何先前的空间都被它隐藏了。因此,我们需要提供我们自己的版本来模仿\addpenalty并添加标签:

\def\addpenaltywithlabel#1#2{%
  \ifvmode
    \if@minipage
    \else
      \if@nobreak
      \else
        \ifdim\lastskip=\z@
          \label{#2}%          <- one place for the label
          \penalty#1\relax
        \else
          \@tempskipb\lastskip
          \vskip -\lastskip
          \label{#2}%          <- and here if the previous skip is "moved"
          \penalty#1%
          \vskip\@tempskipb
        \fi
      \fi
    \fi
  \else
    \@noitemerr
  \fi}

在后面添加第二个标签\addvspace是可以的,因为后面会跟着标题。当然还有很多事情要做,每个实例的标签都需要不同(例如,使用递增的计数器),并且必须为它们生成的页面值编写比较。然后必须编写一些代码来实际利用此信息,使标题出现在顶部(挥手 :-)

相关内容