检测分段命令的层次结构是否受到尊重的最佳方法是什么?

检测分段命令的层次结构是否受到尊重的最佳方法是什么?

是否有一个包可以检查每个小节是否位于父节中,每个子小节是否位于父小节中,等等,否则会发出警告或错误?据我所知没有,但对于文档结构一致性至关重要的文档来说,这将是一个非常方便的功能。

如何检测不尊重分段命令的层次结构,例如,子分段没有父分段?

我当前的方法是重新定义所有分段命令(但顶部命令除外),以检查与上一级分段命令相关联的计数器的值是否非零,如以下 MWE 所示:

\documentclass{article}

\makeatletter
\long\def\subsection{%
\ifnum\value{section}=0\@latex@warning{subsection outside section}\else\fi
\@startsection {subsection}{2}{\z@ }{-3.25ex\@plus -1ex \@minus -.2ex}{1.5ex 
\@plus .2ex}{\normalfont \large \bfseries }
}
\makeatother

\begin{document}
%\section{foo}
\subsection{bar}
\end{document}

但是,如果将上一级分段命令 (在我的 MWE 中为分段) 的编号修改为从 0 开始,则这种方法将无效。您能想到更强大的方法吗?

编辑hyperref如果不遵守层次结构,则会发出警告(参见 Gonzalo 的评论)。但是,用户可以选择忽略它们。如何发出错误而不是警告?

答案1

如果命令对应的分段级别与当前级别相差不止一个,我们会发出警告。只需修补\@startsection以跟踪当前级别并进行检查即可。

\documentclass{article}
\usepackage{etoolbox}

\makeatletter
\pretocmd{\@startsection}{\check@level{#2}}{}{}
\def\check@level#1{%
  \ifnum\numexpr#1-\current@level\relax>\@ne
    \@latex@warning{\@nameuse{level@#1} outside
      \@nameuse{level@\number\numexpr#1-1\relax}}%
  \fi
  \gdef\current@level{#1}}
\@namedef{level@1}{section}
\@namedef{level@2}{subsection}
\@namedef{level@3}{subsubsection}
\@namedef{level@4}{paragraph}
\@namedef{level@5}{subparagraph}
\def\current@level{0}
\makeatother

\begin{document}
\section{A}
\subsection{B}
\subsubsection{C}
\section{D}
\subsubsection{E}
\end{document}

答案2

这是一个想法,使用条件。取消注释任何被注释掉的行将触发错误:

\documentclass{article}

\newif\ifchecksection
\newif\ifchecksubsection
\newif\ifchecksubsubsection
\checksectionfalse
\checksubsectionfalse
\checksubsubsectionfalse

\makeatletter
\renewcommand\section{\@startsection {section}{1}{\z@}%
                                   {-3.5ex \@plus -1ex \@minus -.2ex}%
                                   {2.3ex \@plus.2ex}%
                                   {\global\checksectiontrue\normalfont\Large\bfseries}}
\renewcommand\subsection{\@startsection{subsection}{2}{\z@}%
                                     {-3.25ex\@plus -1ex \@minus -.2ex}%
                                     {1.5ex \@plus .2ex}%
                                     {\global\checksubsectiontrue%
    \ifchecksection\else\@latex@error{Subsection without section}{}\fi%
  \global\checksectionfalse\normalfont\large\bfseries}}
\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}%
                                     {-3.25ex\@plus -1ex \@minus -.2ex}%
                                     {1.5ex \@plus .2ex}%
                                     {\global\checksubsubsectiontrue%
    \ifchecksubsection\else\@latex@error{Subsubsection without subsection}{}\fi%
  \global\checksubsectionfalse\normalfont\normalsize\bfseries}}
\makeatother

\begin{document}

%\subsection{Test Subsection}
\section{Test Section One}
\subsection{Test Subsection One One}
\subsubsection{Test Subsubsection One One}
\section{Test Section Two}
\section{Test Section Three}
%\subsubsection{Test Subsubsection Two -- One}

\end{document}

答案3

以下是与 Gonzalo 的方法类似的方法。主要思想是利用\@stpelt每次\stepcounter调用时调用的辅助函数之一。

\documentclass{article}

\makeatletter
%\newif\if@newsection\@newsectiontrue % Not really needed
\newif\if@newsubsection\@newsubsectionfalse
\newif\if@newsubsubsection\@newsubsubsectionfalse
\newif\if@newparagraph\@newparagraphfalse
\let\old@stpelt\@stpelt
\renewcommand{\@stpelt}[1]{\old@stpelt{#1}\global\@nameuse{@new#1true}}%
\let\old@subsection\subsection
\renewcommand{\subsection}{% Check if allowed to use \subsection
  \if@newsubsection\relax\@newsubsectionfalse\else\@latex@error{Subsection without section}{}\fi%
  \old@subsection}% Continue with regular \subsection
\let\old@subsubsection\subsubsection
\renewcommand{\subsubsection}{% Check if allowed to use \subsubsection
  \if@newsubsubsection\relax\@newsubsubsectionfalse\else\@latex@error{Subsubsection without subsection}{}\fi%
  \old@subsubsection}% Continue with regular \subsubsection
\makeatletter

\begin{document}

\section{A section}
\subsection{A subsection}
\subsubsection{A subsubsection}

\end{document}

对于每个分段命令,都会创建<section>一个条件\if@new<section>,该条件最初设置为 false ( \@new<section>false)。然后,每当计数器<parent>步进时,计数器<child>都会重置\@new<child>true。然后,分段命令中的布尔检查确保可以使用它,否则会引发错误。

注意事项:

  • 即使使用带星号的分段命令变体,错误检查仍会有效。可以删除它,但目前我不知道是否需要这样做。
  • 更多分段命令需要修补,如上例所示,但取决于\documentclass使用情况和使用程度。同样,如果需要,可以进行调整。

相关内容