Latex 动态宏定义

Latex 动态宏定义

我正在尝试动态定义变量。我想要做的是能够以以下方式定义一个人,然后随后调用返回“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也可以用来辨别带星号的变体。

相关内容