为了在由大约 50 个用户编辑的文档(导入的子文档)中强制执行标签规定,我必须重新调整现有的文档结构命令部分、章节等,以遵循预定义的标签方案(使用层次结构级别作为前缀以避免冲突)。
例子胜于文字,下面是我目前对章节的定义(省略细节)。基本上,\chapter
和\chapter*
都扩展了一个可选参数,用于定义一个自动以“ chap:
”为前缀的标签,重复使用旧\chapter
命令。此外,还定义了一个创建参考的命令,其中通过布尔变量选择短参考文本和长参考文本\iflongrefs
。
\RequirePackage{letltxmacro}
\RequirePackage{xargs}
\newcommand*\section@namelong{Section}%
\newcommand*\section@nameshort{Sect.}%
\newcommand*\section@prefix{sect}%
\LetLtxMacro{\section@old}{\section}%
\renewcommand\section{\@ifstar \section@star \section@nostar}%
\newcommandx*\section@nostar[3][1=,3=]{%
\ifx &%
\section@old{#2}%
\else%
\section@old[#1]{#2}%
\fi%
\ifx &%
\else%
\label{\section@prefix:#3}%
\fi%
}%
\newcommandx*\section@star[2][2=]{%
\section@old*{#1}%
\ifx &%
\else%
\label{\section@prefix:#2}%
\fi%
}%
\newcommand*\sectionref[1]{
\iflongrefs
\section@namelong~\ref{\section@prefix:#1}
\else
\section@nameshort\,\ref{\section@prefix:#1}
\fi
}
现在,我需要对部分、小节等进行类似的定义……当然,我可以复制并粘贴此内容,并相应地将其替换\section@XXX
为\part@XXX
等。但是我更喜欢更优雅的解决方案,例如封装(重新)定义的“高阶命令” \extend
。对章节的调用\extend
应类似于下面给出的行,并生成上面看到的所有代码。
\extend{section}{Section}{Sect.}{sect}
我该如何实现它?阅读各种论坛帖子,我觉得\expandafter
这是可行的方法,但我对示例的理解不够,无法让它为我工作。有什么帮助吗?
答案1
在...的帮助下电子工具箱(但仅仅是为了方便):只需将所有改为\section
,#1
但使用\csdef
和\csuse
;重要的是通过加倍#
符号来引用元宏内部定义的宏的参数。
\documentclass{article}
\makeatletter
\RequirePackage{etoolbox}
\RequirePackage{xargs}
\newif\iflongrefs
\newcommand{\extend}[4]{%
\csdef{#1@namelong}{#2}%
\csdef{#1@nameshort}{#3}%
\csdef{#1@prefix}{#4}%
\csletcs{#1@old}{#1}%
\csdef{#1}{\@ifstar{\csuse{#1@star}}{\csuse{#1@nostar}}}%
\expandafter\newcommandx\expandafter*\csname#1@nostar\endcsname[3][1=,3=]{%
\ifx &##1&%
\csuse{#1@old}{##2}%
\else
\csuse{#1@old}[##1]{##2}%
\fi
\ifx &##3&%
\else
\label{\csuse{#1@prefix}:##3}%
\fi
}%
\expandafter\newcommandx\expandafter*\csname#1@star\endcsname[2][2=]{%
\csuse{#1@old}*{##1}%
\ifx &##2&%
\else
\label{\csuse{#1@prefix}:##2}%
\fi
}
\csdef{#1ref}##1{%
\iflongrefs
\csuse{#1@namelong}~\ref{\csuse{#1@prefix}:##1}%
\else
\csuse{#1@nameshort}\,\ref{\csuse{#1@prefix}:##1}%
\fi
}%
}
\makeatother
\extend{section}{Section}{Sect.}{sect}
\extend{subsection}{Subection}{Subsect.}{subsect}
\begin{document}
\section{abc}
\section[aaa]{abc}[def]
\sectionref{def}
{\longrefstrue\sectionref{def}}
\subsection[uuu]{vvv}[www]
\subsectionref{www}
\end{document}
请注意,这\LetLtxMacro
不是必需的,因为\section
和朋友是不是定义为具有可选参数。
已添加 – xparse 版本
代替参数你可能想使用现代解析包裹:
\RequirePackage{etoolbox}
\RequirePackage[log-declarations = false]{xparse}
\newcommand{\extend}[4]{%
\csdef{#1@namelong}{#2}%
\csdef{#1@nameshort}{#3}%
\csdef{#1@prefix}{#4}%
\csletcs{#1@old}{#1}%
\expandafter\DeclareDocumentCommand\csname#1\endcsname{s o m o}{
\IfBooleanTF{##1}
{\csuse{#1@old}*{##3}
% \IfNoValueTF{##4}
% {}
% {\label{\csuse{#1@prefix}:##4}}
}
{\IfNoValueTF{##2}
{\csuse{#1@old}{##3}}
{\csuse{#1@old}[##2]{##3}}
\IfNoValueTF{##4}
{}
{\label{\csuse{#1@prefix}:##4}}
}
}
\expandafter\DeclareDocumentCommand\csname#1ref\endcsname{m}{
\iflongrefs
\csuse{#1@namelong}~\ref{\csuse{#1@prefix}:##1}
\else
\csuse{#1@nameshort}\,\ref{\csuse{#1@prefix}:##1}
\fi
}%
}
这三行注释是因为不清楚标签对于\section*
命令的用途是什么。