如何在序言中定义一个带有可选参数的命令以供宏使用?

如何在序言中定义一个带有可选参数的命令以供宏使用?

我正在尝试编写标签来包含文档信息,该信息可以在序言中声明,然后使用\@institution或包含在标题页中\@module,类似于 LaTeX 已经包含的\title{}方式\@title

我需要一个具有可选“模块编号”的命令,并且可以\module[PH588]{Mathematical Techniques}在序言中声明,以形成像\@mod@no\@mod@title(或类似)的标签,以便在标题页中使用

{\Large \mod@no: \@mod@title \par}

并以大字体显示“PH588:数学技术”。

我对整个宏观业务还很陌生,而且充分熟悉基本知识,例如\newcommand。对于其他信息,我使用

\newcommand{\department}[1]{\renewcommand\@dept{#1}}
    \newcommand{\@dept}{}

定义每个标题元素。

我迄今为止的尝试(没有结果)如下:

1)

\def\module[#1]#2{\gdef\@module[#1]{#2}}
    \def\@module{}

2)

\def\module{\@ifnextchar[{\@module@wno}{\@module@wono}}
    \newcommand{\@module}{}
        \def\@module[#1]#2{#1: #2}
        \def\@module#1{#1}

3)

\newcommand{\module}[2][no module number]{\@ifnextchar[{\renewcommand\@module@no[2]{#1}}{\renewcommand\@module}}
    \def\@module@no[#1]#2{#1}
    \def\@module#1{#1}
    \newcommand\@module@no[#1]#2{#1: #2}
    \newcommand\@module#1{#1}

这些都介于\makeatletter和之间\makeatother

正如您所看到的,我几乎不知道自己在做什么,所以如果您能简单解释一下代码的每个部分是如何运作的以及为什么这会对我有很大帮助!

提前致谢!

答案1

有些事情很难用\@ifnextchar,有些事情很容易用xparse

\documentclass{article}

\usepackage{xcolor}
\usepackage{xparse}

\makeatletter

\providecommand{\@module@no}{}
\providecommand{\@module@title}{}


\newcommand{\module}{%
  \@ifnextchar[{\module@@opt}{\module@@noopt}
}

\newcommand{\module@@opt}[2][no module number]{%
\renewcommand{\@module@no}{#1}%
\renewcommand{\@module@title}{#2}%
}

\newcommand{\module@@noopt}[1]{%
  \module@@opt{#1}%
}


%\@onlypreamble{\module}


\NewDocumentCommand{\Module}{o+m}{%
  \IfValueTF{#1}{%
    \renewcommand{\@module@no}{#1}%
  }{%
    \renewcommand{\@module@no}{no module number}%
  }%
  \renewcommand{\@module@title}{#2}%
}


\newcommand{\printmoduleinfo}{%
{\large \textbf{\@module@no} \textsc{\@module@title}}%
}



\makeatother




\begin{document}

\module[The Fellowship of the Ring]{The Lord Of the Rings}


\printmoduleinfo

\module{The Lord Of the Rings}

\printmoduleinfo

\fbox{\textcolor{blue}{And now again with the xparse stuff}}

\Module[The two Towers]{The Lord Of the Rings}

\printmoduleinfo

\Module{The Lord Of the Rings}

\printmoduleinfo


\end{document}

在此处输入图片描述

答案2

正确的解决方案是

0)

\def\module[#1]#2{\gdef\mod@no{#1}\gdef\mod@title{#2}}

这定义了\module使用 的宏\module[num]{text}。此宏定义\mod@nonum\mod@title为文本。这意味着您稍后可以使用\mod@no扩展为num\mod@title扩展为text。这正是您所需要的。

你的不良尝试:

1)

\def\module[#1]#2{\gdef\@module[#1]{#2}}
\def\@module{}

在用强制参数定义\module[num]{text}宏之后(即,如果你输入的内容与 完全不同,那么 TeX 会打印错误)。这个非常奇怪的宏扩展为。第二行通过设置为空宏是多余的。\@module[num]\@module[num]text\@module\def

2)

\def\module{\@ifnextchar[{\@module@wno}{\@module@wono}}
\newcommand{\@module}{}
\def\@module[#1]#2{#1: #2}
\def\@module#1{#1}

这太复杂而且不好。这定义了\module一个宏,它查找下一个标记。如果是,[\@module@wno执行,否则\@module@wono执行。但这些宏没有定义。接下来,\@module将宏定义为空(与相同\def\@module{})。接下来,将此宏\@module重新定义为带有一个参数在[...]和第二个参数在的宏{}\@module[num]{text}扩展为num: text。最后,\@module再次重新定义宏,现在带有一个参数在{}\@module{text}扩展为text。为什么有三个相同的宏定义?只有最后一个获胜。为什么没有定义\@module@wno\@module@wono宏?

3)

\newcommand{\module}[2][no module number]{%
    \@ifnextchar[{\renewcommand\@module@no[2]{#1}}{\renewcommand\@module}}
\def\@module@no[#1]#2{#1}
\def\@module#1{#1}
\newcommand\@module@no[#1]#2{#1: #2}
\newcommand\@module#1{#1}

这通过定义了\@module@no和作为一个模糊的宏。然后通过 重新定义了相同的宏,但打印错误,因为 A) 宏已经定义,并且 B) 这里的 语法不正确。在第一行,通过 定义为具有一个可选参数和一个强制参数的宏,用法示例或。第二个示例的行为方式为。此宏查找下一个标记,如果是(即用法是),则重新定义,否则重新定义但不执行任何其他操作。@module\def\newcommand\newcommand\newcommand\module\newcommand\module[opt]{text}\module{text}\module[no module number]{text}[\module[opt]{text}[\@module@no\@module

我尝试用 TeX 的眼光来审视你的代码,以表明所有这些代码都是荒谬的。我建议你研究一下\defTeX 中的宏是如何工作的。经过这样的研究,你会发现公认的解决方案也过于复杂了。

答案3

使用 可以很容易地xparse定义一个命令印刷你想要什么:

\usepackage{xparse}

\NewDocumentCommand{\module}{om}{%
  {\Large\IfValueT{#1}{#1: }#2\par}%
}

{#1: }如果您调用,则会打印该部分\module[PH588]{Mathematical Techniques},但不会通过调用打印\module{Mathematical Techniques}

如果您在其他地方需要可选的模块编号和模块标题,那么您可以遵循相同的模式:

\usepackage{xparse}
\makeatletter
\newcommand{\@module@no}{} % initialize
\newcommand{\@module}{} % initialize

\NewDocumentCommand{\module}{om}{%
  \IfValueTF{#1}
    {% there is a module number
     \renewcommand{\@module@no}{#1}%
    }
    {% there is no module number
     \renewcommand{\@module@no}{}%
    }%
  \renewcommand{\@module}{#2}%
  % print the module title
  {\Large\IfValueT{#1}{#1: }#2\par}%
}
\makeatother

您可以使用空性测试来区分当前可用的模块编号,例如

\if\relax\detokenize\expandafter{\@module@no}\relax
  <code for no module number>%
\else
  <code for available module number>%
\fi

相关内容