我正在尝试动态定义变量。我想要做的是能够以以下方式定义一个人,然后随后调用返回“Mr Test”,返回“0400 000 000”并返回“\definePerson{MrTestKey}{Mr Test}{0400 000 000}{[email protected]}
\nameMrTestKey
\phoneMrTestKey
\emailMrTestKey
[电子邮件保护]“。
这是我迄今为止尝试过的...我使用宏,\defineVariable
以便我可以调用\nameMrTestKey
来返回格式化的(\emph
)名称并\nameMrTestKey*
返回未格式化的名称。
% To allow (un)formatted variables
% See http://tex.stackexchange.com/questions/51652/remove-formatting/
\usepackage{xparse}
\NewDocumentCommand\defineVariable{mmm}{%
\NewDocumentCommand#1{s}{\IfBooleanTF{##1}{#3}{#2{#3}}}%
}
% \definePerson{key}{name}{phone}{email}
\newcommand\definePerson[4]{%
\defineVariable\name#1{\emph}{#2}
\defineVariable\phone#1{\emph}{#3}%
\defineVariable\email#1{\emph}{#4}%
}
答案1
您需要使用\csname ... \endcsname
创建具有所需名称的控制序列。因此,以下创建一个名为的宏,其\nameMrTestKey
值为\emph{Mr Test}
\definePerson{MrTestKey}{Mr Test}...
\expandafter\newcommand\csname name#1\endcsname{\emph{#2}}
name
控制序列名称中的是硬编码的,并且是MrTestKey
传递给的第一个参数\definePerson
。
是\expandafter
必需的,因为\newcommand
需要在之后处理\csname
。请参阅后续问题:如何知道我们是否需要 \expandafter?
代码:
\documentclass{article}
\newcommand\definePerson[4]{%
\expandafter\newcommand\csname name#1\endcsname{\emph{#2}}
\expandafter\newcommand\csname phone#1\endcsname{\emph{#3}}
\expandafter\newcommand\csname email#1\endcsname{\emph{#4}}
}
\begin{document}
\definePerson{MrTestKey}{Mr Test}{0400 000 000}{[email protected]}
Name is \nameMrTestKey
Phone is \phoneMrTestKey
Email address is \emailMrTestKey
\end{document}
或者扩展你的 MWE:
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand\defineVariable{mmmm}{%
\global\expandafter\NewDocumentCommand\csname#1#2\endcsname{s}{\IfBooleanTF{##1}{#4}{#3{#4}}}%
}
\newcommand\definePerson[4]{%
\defineVariable{name}{#1}{\emph}{#2}
\defineVariable{phone}{#1}{\emph}{#3}
\defineVariable{email}{#1}{\emph}{#4}
}
\begin{document}
\definePerson{MrTestKey}{Mr Test}{0400 000 000}{[email protected]}
Name is \nameMrTestKey\ or \nameMrTestKey*
Phone is \phoneMrTestKey\ or \phoneMrTestKey*
Email address is \emailMrTestKey\ or \emailMrTestKey*
\end{document}
答案2
我会采取稍微不同的策略,并拥有更紧凑的用户界面。 布鲁诺回答在\NewDocumentCommand 构造了 csname,团队的总体感觉是尝试拥有定义明确的、而非“动态”生成的界面命令。
同时,我会将数据存储在“适当”的结构中,而不是使用\csname
基于 的数组(由于哈希表冲突,后一种方法会对性能产生影响)。所需的信息可以存储在一系列属性列表中:
\documentclass{article}
\ExplSyntaxOn
\prop_new:N \g__JS_name_prop
\prop_new:N \g__JS_telephone_prop
\prop_new:N \g__JS_email_prop
\NewDocumentCommand { \defineperson } { m m m m }
{
\prop_gput:Nnn \g__JS_name_prop {#1} {#2}
\prop_gput:Nnn \g__JS_telephone_prop {#1} {#3}
\prop_gput:Nnn \g__JS_email_prop {#1} {#4}
}
\NewDocumentCommand { \getperson } { s m }
{
\IfBooleanTF #1
{ \emph }
{ \use:n }
{ \prop_item:Nn \g__JS_name_prop {#2} }
}
\NewDocumentCommand { \gettelephone } { s m }
{
\IfBooleanTF #1
{ \emph }
{ \use:n }
{ \prop_item:Nn \g__JS_telephone_prop {#2} }
}
\NewDocumentCommand { \getemail } { s m }
{
\IfBooleanTF #1
{ \emph }
{ \use:n }
{ \prop_item:Nn \g__JS_email_prop {#2} }
}
\ExplSyntaxOff
\defineperson{MrTestKey}{Mr Test}{0400 000 000}{[email protected]}
\begin{document}
\getperson*{MrTestKey} \getemail{MrTestKey}
\end{document}
(我已经为类似电子表格的“数据表”变量类型编写了代码,但这仍处于实验阶段,可能这里不需要。)
答案3
这是一个单独的宏,它定义了使用带星号/无星号的姓名、电话和电子邮件版本所需的命令:
\documentclass{article}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\makeatletter
\let\var@format\relax% Default formatting
\NewDocumentCommand\definePerson{mmmm}{%
\expandafter\gdef\csname name@#1\endcsname{\var@format{#2}}%
\expandafter\gdef\csname phone@#1\endcsname{\var@format{#3}}%
\expandafter\gdef\csname email@#1\endcsname{\var@format{#4}}%
\expandafter\NewDocumentCommand\expandafter{\csname name#1\endcsname}{s}{%
{\IfBooleanTF{##1}{\let\var@format\emph}{}\csname name@#1\endcsname}}%
\expandafter\NewDocumentCommand\expandafter{\csname phone#1\endcsname}{s}{%
{\IfBooleanTF{##1}{\let\var@format\emph}{}\csname phone@#1\endcsname}}%
\expandafter\NewDocumentCommand\expandafter{\csname email#1\endcsname}{s}{%
{\IfBooleanTF{##1}{\let\var@format\emph}{}\csname email@#1\endcsname}}%
}
\makeatother
\begin{document}
\definePerson{MrTestKey}{Mr Test}{1-234-567-8901}{[email protected]}
\definePerson{MrsTestKey}{Mrs Test}{1-234-567-8901}{[email protected]}
\nameMrTestKey\ \phoneMrTestKey*\ \emailMrTestKey \par
\nameMrsTestKey*\ \phoneMrsTestKey\ \emailMrsTestKey*
\end{document}
xparse
但实际上这并不是必需的,因为 LaTeX\@ifstar
也可以用来辨别带星号的变体。