使用 xparse 重写标准类

使用 xparse 重写标准类

我练习了xparse。我重写了 的定义\part。当我尝试以下代码时,一切正常:

\documentclass{book}

\usepackage{xparse}

\newcounter{spart}% makes hyperref work

\makeatletter
\DeclareDocumentCommand{\part}{s m o}%
 {\cleardoublepage\thispagestyle{plain}%
  \if@twocolumn%
   \onecolumn%
   \@tempswatrue%
  \else%
   \@tempswafalse%
  \fi%
  \null\vfil%
 \IfNoValueTF{#3}%
  {\IfBooleanTF{#1}{\m@part*{#2}{#2}}{\m@part{#2}{#2}}}%
  {\IfBooleanTF{#1}{\m@part*{#2}{#3}}{\m@part{#2}{#3}}}}

\DeclareDocumentCommand{\m@part}{s m m}%
 {\IfBooleanTF{#1}{\refstepcounter{spart}% makes hyperref work
               \addcontentsline{toc}{part}{#3}}%
                {\ifnum \c@secnumdepth >-2\relax%
                \refstepcounter{part}%
                \addcontentsline{toc}{part}{\thepart\hspace{1em}#3}%
              \else%
                \addcontentsline{toc}{part}{#3}%
              \fi}%
    \markboth{}{}%
    {\centering%
     \interlinepenalty \@M%
    \normalfont%
  \IfBooleanF{#1}{\ifnum \c@secnumdepth >-2\relax%
              \huge\bfseries \partname~\thepart%
              \par%
              \vskip 20\p@%
              \fi}%
 \Huge \bfseries #2\par}%
\@endpart}
 \makeatother

\usepackage{blindtext}
\usepackage{hyperref}

\begin{document}

\tableofcontents

\part{Teil 1}
\Blinddocument
\part*{Teil 2}
\Blinddocument

\end{document}

看看我的 \m@part 宏。首先我尝试将其命名为 \@part,就像在 book.cls 中调用的那样。但是当我编译它时出现了一些错误。例如:

Use of \@part doesn't match its Definition.

或者

Too many }'s.

我不明白这个问题。为什么它可以与 一起使用\m@part,但不能与 一起使用\@part

谢谢。

答案1

问题在于hyperref重新定义\@part,本质上是为了用计数器做你自己所做的事情spart

无论如何,您不需要使用两个宏。我不会改变部分的语法:可选参数应该放在强制参数之前。

\documentclass{book}
\usepackage{xparse}
\usepackage{hyperref}

\makeatletter
\DeclareDocumentCommand{\part}{s O{#3} m}{%
  \cleardoublepage\thispagestyle{plain}%
  \if@twocolumn
    \onecolumn
    \@tempswatrue
  \else
   \@tempswafalse
  \fi
  \null\vfil
  \IfBooleanTF{#1}
   {% * version
    \csname phantomsection\endcsname % for hyperref
    \addcontentsline{toc}{part}{#2}%
   }
   {% standard version
    \ifnum\c@secnumdepth >-2\relax
      \refstepcounter{part}%
      \addcontentsline{toc}{part}{\thepart\hspace{1em}#2}%
    \else
      \addcontentsline{toc}{part}{#2}%
    \fi
   }%
  \markboth{}{}%
  {% print the title
   \centering \interlinepenalty\@M \normalfont
   \IfBooleanF{#1}
    {% standard version
     \ifnum \c@secnumdepth >-2\relax
       \huge\bfseries \partname~\thepart
       \par
       \vskip 20\p@
     \fi
    }%
   \Huge \bfseries #2\par
  }%
  \@endpart
}
\makeatother

\begin{document}

\tableofcontents

\part{Teil 1}
\part[Ops 2]{Teil 2}
\part*{Teil 3}
\part*[Ops 4]{Teil 4}

\end{document}

请注意,您需要最新版本xparse才能正常工作(2017/02/10 或更高版本)。

在此处输入图片描述

答案2

hyperref重新定义了\addcontentsline\label分段命令,添加了超链接功能等。

如果您的定义不应干扰,则它应该在完成其工作后抓住等hyperref的定义或在之后重新定义它。\@parthyperrefhyperref

将重新定义包装在\AtBeginDocument{...}作品中。

我拿了 OP 的原始版本并把它包裹在\AtBeginDocument{...}钩子中,在我看来,没有必要xparse为此使用最新版本。

\documentclass{book}

\usepackage{xparse}

\newcounter{spart}% makes hyperref work

\usepackage{blindtext}
\usepackage{hyperref}

\makeatletter
\AtBeginDocument{%
\DeclareDocumentCommand{\part}{s m o}%
 {\cleardoublepage\thispagestyle{plain}%
  \if@twocolumn%
   \onecolumn%
   \@tempswatrue%
  \else%
   \@tempswafalse%
  \fi%
  \null\vfil%
 \IfNoValueTF{#3}%
  {\IfBooleanTF{#1}{\m@part*{#2}{#2}}{\m@part{#2}{#2}}}%
  {\IfBooleanTF{#1}{\m@part*{#2}{#3}}{\m@part{#2}{#3}}}}

\DeclareDocumentCommand{\m@part}{s m m}%
 {\IfBooleanTF{#1}{\refstepcounter{spart}% makes hyperref work
               \addcontentsline{toc}{part}{#3}}%
                {\ifnum \c@secnumdepth >-2\relax%
                \refstepcounter{part}%
                \addcontentsline{toc}{part}{\thepart\hspace{1em}#3}%
              \else%
                \addcontentsline{toc}{part}{#3}%
              \fi}%
    \markboth{}{}%
    {\centering%
     \interlinepenalty \@M%
    \normalfont%
  \IfBooleanF{#1}{\ifnum \c@secnumdepth >-2\relax%
              \huge\bfseries \partname~\thepart%
              \par%
              \vskip 20\p@%
              \fi}%
 \Huge \bfseries #2\par}%
\@endpart}
}
\makeatother



\begin{document}

\tableofcontents

\part{Teil 1}
\Blinddocument
\part*{Teil 2}
\Blinddocument

\end{document}

相关内容