我正在为一位朋友设置一个骨架简历包,供他自定义,我想让它尽可能方便用户使用。为此,我使用了keyval
和xparse
。
\begin{filecontents}{setup.sty}
\RequirePackage{xparse}
\RequirePackage{keyval}
\define@key{position}{title} {\def{\position@title} {#1}}
\define@key{position}{date} {\def{\position@date} {#1}}
\define@key{position}{company}{\def{\position@company}{#1}}
\define@key{position}{place} {\def{\position@place} {#1}}
\DeclareDocumentEnvironment{position}{m}{%
\begingroup
\IfNoValueTF{#1}
{\setkeys{position}{title={},date={},company={},place={}}}
{\setkeys{position}{title={},date={},company={},place={},#1}}
\begin{description}
\item[Title] \position@title
\item[Date] \position@date
\item[Company] \position@company
\item[Place] \position@place
\end{description}
\endgroup
}{}
\end{filecontents}
\documentclass{article}
\usepackage{setup}
\begin{document}
\begin{position}{title=hello}
Hey
\end{position}
\end{document}
在我看来,这似乎是xparse
and的一个相当标准的用法keyval
,所以我很可能错过了一些相当简单和 Read-The-Fine-Manual-y 的东西,但我找不到任何错误,而且错误消息对我来说仍然很神秘——我以前从未遇到过。以下是错误消息的全部内容:
ERROR: Missing control sequence inserted. --- TeX said --- <inserted text> \inaccessible l.55 \begin{position}{title=hello} --- HELP --- This is probably caused by a \newcommand, \renewcommand, \newlength, or \newsavebox command whose first argument is not a command name.
这里发生了什么?我怎样才能让 TeX 再次正常运行?
顺便说一句,如果有人愿意xkeyval
在他们的答案中给出等效的解决方案,我总是很高兴学到一些新东西:-)。
我被 AUCTeX 宠坏了;日志文件中还有更多错误可能更有帮助:
... style imports ...
! Missing control sequence inserted.
<inserted text>
\inaccessible
l.56 \begin{position}{title=hello}
! Missing control sequence inserted.
<inserted text>
\inaccessible
l.56 \begin{position}{title=hello}
! Missing control sequence inserted.
<inserted text>
\inaccessible
l.56 \begin{position}{title=hello}
! Missing control sequence inserted.
<inserted text>
\inaccessible
l.56 \begin{position}{title=hello}
! Missing control sequence inserted.
<inserted text>
\inaccessible
l.56 \begin{position}{title=hello}
! Undefined control sequence.
\environment position code ...le] \position@title
\item [Date] \position@dat...
l.56 \begin{position}{title=hello}
! Undefined control sequence.
\environment position code ...ate] \position@date
\item [Company] \position@...
l.56 \begin{position}{title=hello}
! Undefined control sequence.
\environment position code ...] \position@company
\item [Place] \position@pl...
l.56 \begin{position}{title=hello}
! Undefined control sequence.
\environment position code ...ce] \position@place
\end {description} \endgroup l.56 \begin{position}{title=hello}
... see transcript file for additional information, etc. etc. ...
答案1
\def
是一个具有语法的原始命令
\def<control sequence><parameter text>{<replacement text>}
其中<control sequence>
表示以 开头的控制序列名称,\
或表示活动字符。 后面的任何其他标记\def
都是非法的,TeX 会尝试通过插入名为 的特殊控制序列来恢复\inaccessible
。 错误消息非常清楚:
! Missing control sequence inserted.
<inserted text>
\inaccessible
<to be read again>
{
l.18 \def{
\position@title} {hi}
您可以看到 TeX 停止的位置:它{
在 之后发现\def
;有问题的{
标记已放回输入流中,并将再次读取,就像尚未读取一样。在 和 之间,\def
TeX{
插入了\inaccessible
,您仍然可以通过键入 来删除它1
,然后i\foo
插入您可能忘记添加的控制序列名称(至少 TeX 是这么想的)。
如果你对低级 TeX 命令不太有信心,你仍然可以坚持使用 LaTeX 的模型。只需在命令\position@title
前进行初始化\define@key
:
\newcommand{\position@title}{}
\define@key{position}{title}{\renewcommand{\position@title}{#1}}
\newcommand
允许在或的第一个参数周围使用括号\renewcommand
(LaTeX 手册总是使用它们)但不是必需的。
实际上,初始化容器可以避免稍后设置键时出现笨拙的代码。
让我们看看你的代码:
\DeclareDocumentEnvironment{position}{m}{%
\begingroup
\IfNoValueTF{#1}
{\setkeys{position}{title={},date={},company={},place={}}}
{\setkeys{position}{title={},date={},company={},place={},#1}}
\begin{description}
\item[Title] \position@title
\item[Date] \position@date
\item[Company] \position@company
\item[Place] \position@place
\end{description}
\endgroup
}{}
没有必要设置具有空值的键,因为如果您已经初始化它们,则默认值无论如何都是空的。
\IfNoValueTF
另一件需要注意的事情是,意志的真正分支绝不\begingroup
注意:该函数用于可选参数,而不是强制参数。和也不需要\endgroup
,因为键将设置在由 打开的组中\begin{position}
。
因此更有效的代码是
\newcommand{\position@title} {}
\newcommand{\position@date} {}
\newcommand{\position@company}{}
\newcommand{\position@place} {}
\define@key{position}{title} {\renewcommand{\position@title} {#1}}
\define@key{position}{date} {\renewcommand{\position@date} {#1}}
\define@key{position}{company}{\renewcommand{\position@company}{#1}}
\define@key{position}{place} {\renewcommand{\position@place} {#1}}
\DeclareDocumentEnvironment{position}{m}
{%
\setkeys{position}{#1}
\begin{description}
\item[Title] \position@title
\item[Date] \position@date
\item[Company] \position@company
\item[Place] \position@place
\end{description}
}{}
我建议采用稍微不同的方法:您可以使用l3keys
。
\ExplSyntaxOn
\keys_define:nn { sean/position }
{
title .tl_set:N = \l_sean_position_title_tl,
date .tl_set:N = \l_sean_position_date_tl,
company .tl_set:N = \l_sean_position_company_tl,
place .tl_set:N = \l_sean_position_place_tl,
}
\NewDocumentEnvironment{position}{m}
{
\begin{description}
\keys_set:nn { sean/position } { #1 }
\item[Title] \l_sean_position_title_tl
\item[Date] \l_sean_position_date_tl
\item[Company] \l_sean_position_company_tl
\item[Place] \l_sean_position_place_tl
\end{description}
}{}
\ExplSyntaxOff
和\keys_define:nn
功能\keys_set:nn
已可用\usepackage{xparse}
。
答案2
来自TeX 书(第 20 章 定义(也称为宏),第 203 页):
...让我们看看控制 TeX 宏的精确规则。定义具有一般形式
\def<control sequence><parameter text>{<replacement text>}
其中
<parameter text>
不包含,并且中braces
的所有{
和都正确嵌套。此外,符号具有特殊意义:在 中,第一次出现的 后面必须跟 ,下一次跟 ,依此类推;最多允许九个 。在每个 中 , 后面必须跟在 之后出现的数字 ,否则 后面 应该跟另一个 。后一种情况代表宏展开时的单个 标记;前一种情况代表插入相应的参数。}
<replacement text>
#
<parameter text>
#
1
2
#
<replacement text>
#
#
<parameter text>
#
#
#
由此可见,<control sequence>
不需要支撑。
关于您使用keyval
,你也可以使用xkeyval
的“命令键” \define@cmdkey
。从xkeyval
文档(部分3.2 命令键,第 5 页):
以下两行也用同样的键宏实现了一个键:
\define@cmdkey{fam}[my@]{key}[none]{value: \my@key}% xkeyval syntax \define@key{fam}{key}[none]{\def\mykey{#1}value: \my@key}% keyval syntax
答案3
这实际上没有什么与 {xparse}、{keyval} 或 {environments} 完全无关。我所需要做的就是从 中删除括号\def
。
我正在尝试 Joseph Wright 的TUGBoat 文章在keyval
接口上,并决定尝试第 111 页的建议,position@title
即在实际制作键之前定义容器宏(例如)。这弹出了一个不同的错误,但肯定更明确:
ERROR: Missing control sequence inserted.
--- TeX said ---
<inserted text>
\inaccessible
l.18 \def{
\position@title} {hi}
--- HELP ---
This is probably caused by a \newcommand, \renewcommand, \newlength,
or \newsavebox command whose first argument is not a command name.
从这里可以相对明显地看出,{
和}
字符是问题的根源,尽管我还是不知道为什么。 为此目的所获得的任何额外资源都将受到高度赞赏。