这是具有 keyval 选项的类,由 keyval 对列表组成。 在这个问题的答案,斯基尔蒙展示了如何编写一个提供命令的类,\people
该命令采用以逗号分隔的键值对组列表,然后在列表中排版该信息。
我想另外定义两个新的宏\specialpersonone
和一个可选宏,它们将排版在该列表的开头以及另一页上的表格中。除了另一个键值对之外,\specialpersontwo
它们还将具有相同的键值对。\people
field
这是一个不起作用的最小示例。我试图遵循斯基尔蒙以前做过,但我不太明白如何expkv
处理参数。似乎在我尝试排版参数之前,参数没有被处理。
非工作mwe
我的类名.cls
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}
\LoadClass[oneside,letterpaper]{memoir}
\RequirePackage{expkv-def}
\ekvdefinekeys{myclass/people}
{
long store title = \myclass@people@title
,long store role = \myclass@people@role
,long store name = \myclass@people@name
}
\ekvsetdef\myclass@people@options{myclass/people}
\newcommand\people[1]{\edef\myclass@people{\unexpanded{#1}}}
\ekvdefinekeys{myclass/special-person-one}
{
long store title = \myclass@specialpersonone@title
,long store role = \myclass@specialpersonone@role
,long store name = \myclass@specialpersonone@name
,long store field = \myclass@specialpersonone@field
}
\ekvsetdef\myclass@specialpersonone@options{myclass/special-person-one}
\newcommand\specialpersonone[1]{\edef\myclass@specialpersoone{\unexpanded{#1}}}
\ekvdefinekeys{myclass/special-person-two}
{
long store title = \myclass@specialpersontwo@title
,long store role = \myclass@specialpersontwo@role
,long store name = \myclass@specialpersontwo@name
,long store field = \myclass@specialpersontwo@field
}
\ekvsetdef\myclass@specialpersontwo@options{myclass/special-person-two}
\newcommand\specialpersontwo[1]{\edef\myclass@specialpersotwo{\unexpanded{#1}}}
\newcommand*\mypeople[1]
{%
\unless\ifx\myclass@people\@empty
\begin{itemize}
\item \myclass@specialpersonone@title\space\myclass@specialpersonone@name, Special Role 1
\unless\ifx\myclass@specialpersontwo@\empty
\item \myclass@specialpersontwo@title\space\myclass@specialpersontwo@name, Special Role 2
\fi
\expandafter\ekvcsvloop\expandafter\mypeople@aux\expandafter{#1}%
\end{itemize}%
\fi
}
\newcommand\mypeople@aux[1]
{%
\item
\begingroup
\myclass@people@options{#1}%
\unless\ifx\myclass@people@title\@empty
\myclass@people@title\space
\fi
\myclass@people@name
\unless\ifx\myclass@people@role\@empty
, \myclass@people@role
\fi
\endgroup
}
\newcommand{\makemypage}{%
\pagestyle{empty}
\thispagestyle{empty}
\begin{titlingpage}
\begin{center}
\mypeople{\myclass@people}
\end{center}
\end{titlingpage}}
\newcommand{\makemytablepage}{%
\pagestyle{empty}
\thispagestyle{empty}
\begin{titlingpage}
\begin{center}
\begin{tabular}{ll}
Special people ~ & \myclass@specialpersonone@name\\
~ & \myclass@specialpersonone@field\\
~ &~\\
\unless\ifx\myclass@specialpersontwo@\empty
~ & \myclass@specialpersontwo@name\\
~ & \myclass@specialpersontwo@field\\
~ & ~\\
\fi
\end{tabular}
\end{center}
\end{titlingpage}}
\endinput
我的文件.tex
\documentclass[]{myclass}
\specialpersonone{title={Doctor}, name={Special Person}, field={Field 1}}
\specialpersontwo{title={Doctor}, name={Second Person}, field={Field 2}}
\people{
{title={Doctor},name={John Smith},role={Role}},
{title={Doctor},name={Jane Smith},role={}}}
\begin{document}
\makemypage
\makemytablepage
\end{document}
答案1
expkv
\myclass@people@options
在您调用或\myclass@specialpersonone@options
或的地方解析选项,并\myclass@specialpersontwo@options
使用key = value列表作为参数(或\ekvset{<set>}
,\ekvsetdef\<macro>{<set>}
只是为此定义一个快捷方式(这确实比执行要快一点\ekvset{<set>}
);这对于所有key = value接口都相同,您必须调用前端宏来实际设置值)。 我上一个答案中的代码在里面完成了这一步\mypeople@aux
。 由于您从未为特殊人员执行过此操作,因此他们不会将值分配给内部。
下面是两个版本,输入语法略有不同(我更喜欢第二个,但选择权在您手中)。优点是输入不太复杂(少了一个键,这从来都不是可选的,每个人都应该有一个名字!)。
CSV 列表版本
但是,将完整的 key=value 列表存储在宏中(就像使用\specialpersonone
和 那样\specialpersontwo
)对于这些宏来说并不是必需的,因为这不是您想要在以后解析的 csv 列表。因此,我将它们更改为当场进行 key=value 解析。然后,分配的值通过临时辅助宏从组中偷运出来\myclass@tmp
。
此外,为了减少重复代码,我改变了 key=value 设置的结构。现在有一个针对特殊人员的集合,如果使用未知密钥,则会转到针对人员的一般集合(通过unknown redirect
)。
我还创建了两个便利宏来减少测试量\ifx\@empty
,以及一个用于特殊人员输出的便利宏。
类文件:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}
\LoadClass[oneside,letterpaper]{memoir}
\RequirePackage{expkv-def}
\RequirePackage{booktabs}
\ekvdefinekeys{myclass/people}
{
long store title = \myclass@people@title
,long store role = \myclass@people@role
,long store name = \myclass@people@name
}
\ekvsetdef\myclass@people@options{myclass/people}
\ekvdefinekeys{myclass/specialpeople}
{
long store field = \myclass@people@field
,unknown redirect = myclass/people
}
\ekvsetdef\myclass@specialpeople@options{myclass/specialpeople}
% initialise macros
\newcommand*\myclass@people{}
\newcommand\people[1]{\edef\myclass@people{\unexpanded{#1}}}
% special persons are handled differently, the options are evaluated on the spot
% and then stored in other macros via \myclass@copyspecialperson calls
\newcommand\specialpersonone{\specialperson@aux{A}}
\newcommand\specialpersontwo{\specialperson@aux{B}}
\newcommand\specialperson@aux[2]
{%
% group to keep the assignments to \myclass@people@role etc. local
\begingroup
\myclass@specialpeople@options{#2}%
% smuggle out the settings inside of \myclass@tmp (with
% \myclass@copyspecialperson)
\def\myclass@tmp{}%
\ekvcsvloop{\myclass@copyspecialperson{#1}}{title,role,name,field}%
% close the group after expanding the temporary macro once
\expandafter
\endgroup
\myclass@tmp
}
\newcommand\myclass@copyspecialperson[2]
{%
\edef\myclass@tmp
{%
\unexpanded\expandafter{\myclass@tmp}% keep old contents
\def
\unexpanded\expandafter{\csname myclass@specialperson@#1@#2\endcsname}%
{%
\unexpanded\expandafter\expandafter\expandafter
{\csname myclass@people@#2\endcsname}%
}%
}%
}
% to detect whether the special persons were used we initialise the @name macros
\newcommand*\myclass@specialperson@A@name{}
\newcommand*\myclass@specialperson@B@name{}
\newcommand\myclass@unlessempty[3]
{%
% #1: macro
% #2: pre
% #3: post
\unless\ifx\@empty#1%
\expandafter\@secondoftwo
\fi
\@gobble{#2#1#3}%
}
\newcommand\myclass@unlessempty@special[1]
{\expandafter\myclass@unlessempty\csname myclass@specialperson@#1\endcsname}
\newcommand\myclass@specialperson@output[1]
{%
\myclass@unlessempty@special{#1@name}
{%
\item
\myclass@unlessempty@special{#1@title}{}{ }%
}%
{%
\myclass@unlessempty@special{#1@role}{, }{}%
% \myclass@unlessempty@special{#1@field}{, }{}% TODO: is this needed?
}%
}
\newcommand*\mypeople[1]
{%
\unless\ifx\myclass@people\@empty
\begin{itemize}
\myclass@specialperson@output{A}%
\myclass@specialperson@output{B}%
\ekvcsvloop\mypeople@aux{#1}%
\end{itemize}%
\fi
}
\newcommand\mypeople@aux[1]
{%
\item
\begingroup
\myclass@people@options{#1}%
\myclass@unlessempty\myclass@people@title{}{ }%
\myclass@people@name
\myclass@unlessempty\myclass@people@role{, }{}%
\endgroup
}
\newcommand{\makemypage}{%
\pagestyle{empty}
\thispagestyle{empty}
\begin{titlingpage}
\begin{center}
\expandafter\mypeople\expandafter{\myclass@people}
\end{center}
\end{titlingpage}}
\newcommand{\makemytablepage}
{%
% check whether at least one of the two special persons was used
\begingroup
\edef\myclass@tmp
{%
\unexpanded\expandafter{\myclass@specialperson@A@name}%
\unexpanded\expandafter{\myclass@specialperson@B@name}%
}%
\expandafter
\endgroup
\unless\ifx\myclass@tmp\@empty
\pagestyle{empty}
\thispagestyle{empty}
\begin{titlingpage}
\begin{center}
\begin{tabular}{ll}
Special people
\myclass@unlessempty@special{A@name}{&}%
{%
\\
\myclass@unlessempty@special{A@field}{&}{\\}%
\addlinespace
}%
\myclass@unlessempty@special{B@name}{&}%
{%
\\
\myclass@unlessempty@special{B@field}{&}{\\}%
}%
\end{tabular}
\end{center}
\end{titlingpage}%
\fi
}
\endinput
文档:
\documentclass[]{myclass}
\specialpersonone{title={Doctor}, name={Special Person}, field={Field 1}}
\specialpersontwo{title={Doctor}, name={Second Person}, field={Field 2}}
\people{
{title={Doctor},name={John Smith},role={Role}},
{title={Doctor},name={Jane Smith}}}
\begin{document}
\makemypage
\makemytablepage
\end{document}
输出:
和
名称={key=val} 版本
由于使用建议的接口所需的更改<name>={<key=val>}
很少,我决定只提供它。如果 a<name>
应该包含逗号,您可以使用它{<name>}={<key=val>}
来保护该名称。如果名称不需要 atitle
或 ,role
您可以直接使用它而不使用={<key=val>}
。
类文件:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}
\LoadClass[oneside,letterpaper]{memoir}
\RequirePackage{expkv-def}
\RequirePackage{booktabs}
\ekvdefinekeys{myclass/people}
{
long store title = \myclass@people@title
,long store role = \myclass@people@role
}
\ekvsetdef\myclass@people@options{myclass/people}
\ekvdefinekeys{myclass/specialpeople}
{
long store field = \myclass@people@field
,unknown redirect = myclass/people
}
\ekvsetdef\myclass@specialpeople@options{myclass/specialpeople}
% initialise macros
\newcommand*\myclass@people{}
\newcommand\people[1]{\edef\myclass@people{\unexpanded{#1}}}
% special persons are handled differently, the options are evaluated on the spot
% and then stored in other macros via \myclass@copyspecialperson calls
\newcommand\specialpersonone{\specialperson@aux{A}}
\newcommand\specialpersontwo{\specialperson@aux{B}}
\newcommand\specialperson@aux[3]
{%
\expandafter\def\csname myclass@specialperson@#1@name\endcsname{#2}%
% group to keep the assignments to \myclass@people@role etc. local
\begingroup
\myclass@specialpeople@options{#3}%
% smuggle out the settings inside of \myclass@tmp (with
% \myclass@copyspecialperson)
\def\myclass@tmp{}%
\ekvcsvloop{\myclass@copyspecialperson{#1}}{title,role,field}%
% close the group after expanding the temporary macro once
\expandafter
\endgroup
\myclass@tmp
}
\newcommand\myclass@copyspecialperson[2]
{%
\edef\myclass@tmp
{%
\unexpanded\expandafter{\myclass@tmp}% keep old contents
\def
\unexpanded\expandafter{\csname myclass@specialperson@#1@#2\endcsname}%
{%
\unexpanded\expandafter\expandafter\expandafter
{\csname myclass@people@#2\endcsname}%
}%
}%
}
% to detect whether the special persons were used we initialise the @name macros
\newcommand*\myclass@specialperson@A@name{}
\newcommand*\myclass@specialperson@B@name{}
\newcommand\myclass@unlessempty[3]
{%
% #1: macro
% #2: pre
% #3: post
\unless\ifx\@empty#1%
\expandafter\@secondoftwo
\fi
\@gobble{#2#1#3}%
}
\newcommand\myclass@unlessempty@special[1]
{\expandafter\myclass@unlessempty\csname myclass@specialperson@#1\endcsname}
\newcommand\myclass@specialperson@output[1]
{%
\myclass@unlessempty@special{#1@name}
{%
\item
\myclass@unlessempty@special{#1@title}{}{ }%
}%
{%
\myclass@unlessempty@special{#1@role}{, }{}%
% \myclass@unlessempty@special{#1@field}{, }{}% TODO: is this needed?
}%
}
\newcommand*\mypeople[1]
{%
\unless\ifx\myclass@people\@empty
\begin{itemize}
\myclass@specialperson@output{A}%
\myclass@specialperson@output{B}%
\ekvparse{\item\@firstofone}\mypeople@aux{#1}%
\end{itemize}%
\fi
}
\newcommand\mypeople@aux[2]
{%
\item
\begingroup
\myclass@people@options{#2}%
\myclass@unlessempty\myclass@people@title{}{ }%
#1%
\myclass@unlessempty\myclass@people@role{, }{}%
\endgroup
}
\newcommand{\makemypage}{%
\pagestyle{empty}
\thispagestyle{empty}
\begin{titlingpage}
\begin{center}
\expandafter\mypeople\expandafter{\myclass@people}
\end{center}
\end{titlingpage}}
\newcommand{\makemytablepage}
{%
% check whether at least one of the two special persons was used
\begingroup
\edef\myclass@tmp
{%
\unexpanded\expandafter{\myclass@specialperson@A@name}%
\unexpanded\expandafter{\myclass@specialperson@B@name}%
}%
\expandafter
\endgroup
\unless\ifx\myclass@tmp\@empty
\pagestyle{empty}
\thispagestyle{empty}
\begin{titlingpage}
\begin{center}
\begin{tabular}{ll}
Special people
\myclass@unlessempty@special{A@name}{&}%
{%
\\
\myclass@unlessempty@special{A@field}{&}{\\}%
\addlinespace
}%
\myclass@unlessempty@special{B@name}{&}%
{%
\\
\myclass@unlessempty@special{B@field}{&}{\\}%
}%
\end{tabular}
\end{center}
\end{titlingpage}%
\fi
}
\endinput
文档:
\documentclass[]{myclass}
\specialpersonone{Special Person}{title={Doctor}, field={Field 1}}
\specialpersontwo{Second Person}{title={Doctor}, field={Field 2}}
\people
{
John Smith={title={Doctor},role={Role}}
,Jane Smith={title={Doctor}}
,John Doe
}
\begin{document}
\makemypage
\makemytablepage
\end{document}
输出:与上文类似(除了附加项目符号“• John Doe”)。