如何定义和使用定义宏的宏?

如何定义和使用定义宏的宏?

我是 TeX 和 LaTeX 的新手,在定义和使用定义其他宏的宏时遇到了麻烦。我读过如何做到这一点(例如,https://en.wikibooks.org/wiki/LaTeX/Plain_TeX#Plain_TeX_macros,以及本网站上之前的各种问题),但我就是无法让它工作。

考虑以下故意冗长的代码片段:

\def\apcodeEWR {EWR}
\def\apnameEWR {Newark Liberty International Airport}
\def\apcityEWR {Newark, NJ, USA}

\def\apcodeORY {ORY}
\def\apnameORY {Paris Orly Airport}
\def\apcityORY {Orly, France}

\def\apdescriptionEWR {\apnameEWR, located in \apcityEWR, has the airport code \apcodeEWR.}
\def\apdescriptionORY {\apnameORY, located in \apcityORY, has the airport code \apcodeORY.}

\begin{itemize}
    \item \apdescriptionEWR
    \item \apdescriptionORY
\end{itemize}

这将输出我期望的结果:

* Newark Liberty International Airport, located in Newark, NJ, USA, has the airport code EWR.
* Paris Orly Airport, located in Orly, France, has the airport code ORY.

但我想做类似的事情:

\apdefine{EWR}{Newark Liberty International Airport}{Newark, NJ, USA}
\apdefine{ORY}{Paris Orly Airport}{Paris, France}

\begin{itemize}
    \apdescribe{EWR}
    \apdescribe{ORY}
\end{itemize}

我想首先克服这个障碍,但我觉得我应该提一下,最终我真的很想做这样的事情:

\begin{itemize}
    \foreachairport\apdescribe
\end{itemize}

因此,现在我正在尝试制作那个“apdefine”宏。根据我之前链接的书,我正在尝试这个(之前尝试过很多其他方法):

\def\apdefine#1#2#3 {
    \expandafter\def\csnameapcode#1\endcsname {##1}
    \expandafter\def\csnameapname#1\endcsname {##2}
    \expandafter\def\csnameapcity#1\endcsname {##3}
}

编译没有错误。但是我尝试使用它:

\apdefine{IBA}{Ibadan Airport}{Ibadan, Oyo, Nigeria}

我收到九个错误,全部在该行。它们是以下三组:

Undefined control sequence. ...IBA}{Ibadan Airport}{Ibadan, Oyo, Nigeria}
Missing control sequence inserted. ...IBA}{Ibadan Airport}{Ibadan, Oyo, Nigeria}
Illegal parameter number in definition of \inaccessible. ...IBA}{Ibadan Airport}{Ibadan, Oyo, Nigeria}

我做错了什么?我该如何正确做?或者,如果有一种完全不同的方法可以用来做我想做的事情,那是什么?谢谢。

答案1

调用\apdefine定义三个参数变量以及描述变量。然后,它将机场代码附加到名为 的逗号分隔列表中\airportlist

通过 定义每个机场后\apdefine,应该调用\readlist,这将创建一个listofitems名为 的数组\airports,可以方便地在循环中使用\foreachitem

\documentclass{article}
\usepackage{listofitems}
\ignoreemptyitems
\def\airportlist{}
\newcommand\apdefine[3]{%
  \expandafter\def\csname apcode#1\endcsname{#1}%
  \expandafter\def\csname apname#1\endcsname{#2}%
  \expandafter\def\csname apcity#1\endcsname{#3}%
  \expandafter\def\csname apdescription#1\endcsname{%
    #2, located in #3, has the airport code #1.}%
  \expandafter\def\expandafter\airportlist\expandafter{\airportlist#1,}
}
\apdefine{EWR}{Newark Liberty International Airport}{Newark, NJ, USA}
\apdefine{ORY}{Paris Orly Airport}{Paris, France}
\apdefine{IBA}{Ibadan Airport}{Ibadan, Oyo, Nigeria}
\readlist\airports{\airportlist}
\begin{document}
\begin{itemize}
    \foreachitem\z\in\airports[]{\item \csname apdescription\z\endcsname}
\end{itemize}
\end{document}

在此处输入图片描述

答案2

您可以使用prop列表来expl3存储每个条目的相关数据,然后将每个条目的键存储在列表中。定义一个以文本为参数的seq命令,您可以循环遍历列表并打印文本。\apdescribetextseq

\apdefine接受三个参数:机场代码、名称和地址。
\apdescribe接受机场代码作为参数并使用打印其信息\apdescribetext
\apdescribeall循环遍历机场列表并打印每一个机场。

代码如下:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \g_vesterman_airports_seq
\NewDocumentCommand \apdefine { mmm }
  {
    \seq_gput_right:Nn \g_vesterman_airports_seq {#1}
    \prop_new:c { g_vesterman_#1_prop }
    \prop_gput:cnn { g_vesterman_#1_prop } { name } {#2}
    \prop_gput:cnn { g_vesterman_#1_prop } { address } {#3}
  }
\NewDocumentCommand \apdescribe { m }
  {
    \exp_args:Nff \apdescribetext
      { \prop_item:cn { g_vesterman_#1_prop } { name } }
      { \prop_item:cn { g_vesterman_#1_prop } { address } }
      {#1}
  }
\NewDocumentCommand \apdescribeall { }
  { \seq_map_function:NN \g_vesterman_airports_seq \apdescribe }
\ExplSyntaxOff

\newcommand{\apdescribetext}[3]{\item #1, located in #2, has the airport code #3.}

\apdefine{EWR}{Newark Liberty International Airport}{Newark, NJ, USA}
\apdefine{ORY}{Paris Orly Airport}{Paris, France}

\begin{document}
\begin{itemize}
    \apdescribeall
\end{itemize}
\end{document}

相关内容