将命令应用于以 \and 分隔的元素列表

将命令应用于以 \and 分隔的元素列表

我正在尝试构建一个类似于该\author命令的命令。它需要一个参数,实际上是一个用 分隔的参数列表\and。该命令需要将另一个命令(如\underline或 )\emph应用于列表的每个元素。我目前的方法是

\documentclass{minimal}
\newcommand{\mylist}[1]{%
    \def\and{\noexpand\endgroup \noexpand\underline\noexpand\begingroup}%
    \edef\myinternallist{\noexpand\underline\noexpand\begingroup #1\noexpand\endgroup}%
    \show\myinternallist%
    \myinternallist%
}
\begin{document}
    \mylist{Element1 \and Element2}
\end{document}

\show\myinternallist产生

> \myinternallist=macro:
->\underline \begingroup Element1 \endgroup \underline \begingroup Element2\endgroup .

在我这个外行人看来,这没什么问题。但是,上面的代码无法编译,我也不知道为什么无法编译。预期结果如下所示: 在此处输入图片描述

答案1

你确实得到了

\underline \begingroup Element1 \endgroup \underline \begingroup Element2\endgroup

但不幸的是\underline\begingroup Element1 \endgroup这是非法的,因为\begingroup\endgroup不能用于限定宏参数。

有各种各样的工具可以实现这一点;我将展示一个基于expl3未来 LaTeX3 的编程层的解决方案。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\mylist}{ O{\underline} m }
 {
  % transfer control to an internal function
  \porst_mylist:nn { #1 } { #2 }
 }

\seq_new:N \l__porst_list_items_seq
\seq_new:N \l__porst_list_output_seq

\cs_new_protected:Npn \porst_mylist:nn #1 #2
 {
  % clear the output sequence
  \seq_clear:N \l__porst_list_output_seq
  % split the input at \and
  \seq_set_split:Nnn \l__porst_list_items_seq { \and } { #2 }
  % append each item to the output sequence
  \seq_map_inline:Nn \l__porst_list_items_seq
   {
    % #1 is the given argument, ##1 represents the current item
    \seq_put_right:Nn \l__porst_list_output_seq { #1 { ##1 } }
   }
  % output the sequence with something between items
  \seq_use:Nn \l__porst_list_output_seq {,~} % adjust
 }
\ExplSyntaxOff

\begin{document}

\mylist{Element1 \and Element2}

\mylist[\emph]{Element1 \and Element2}

\end{document}

第一步是在\and标记处拆分输入;尾随和前导空格将被删除;第二步是将“格式化”的项目存储在另一个序列中,以便在项目之间使用一些分隔符来使用该序列。

在此处输入图片描述

另一个可能的工具是etoolbox;但是,如您所见,它要复杂得多。

\documentclass{article}
\usepackage{etoolbox}

\makeatletter
\DeclareListParser*{\andlist@do}{\and}
\newcommand{\andlist@sep}{, }
\newcommand{\mylist}[2][\underline]{%
  \def\andlist@output{\@gobble}%
  \andlist@do{\andlist@handler{#1}}{#2}%
  \andlist@output
}
\appto\nocorrlist{\andlist@sep}

\newcommand{\andlist@handler}[2]{%
  \appto\andlist@output{\andlist@sep#1{#2\unskip}}%
}
\makeatother

\begin{document}

\mylist{Element1 \and Element2}

\mylist[\emph]{Element1\and Element2}

\end{document}

答案2

如果您想要一个不需要包的解决方案,请使用括号{},但您需要在定义中平衡它们。要在展开时隐藏它们,只需使用\iffalse.. \fi

\def\and{\unskip\iffalse{\fi} \noexpand\underline{\iffalse}\fi}%
\protected@edef\myinternallist{\noexpand\underline{#1}}%

\edef不能与任意内容一起使用,因此我使用,这意味着您必须用..\protected@def将整个定义括起来。我还添加了(删除每个块末尾的空格)和一个空格。\makatletter\makeatother\unskip

答案3

这里是常见的解决方案,不需要任何expl3,etoolbox等,\and宏可以根据需要定义,我们只需要三行宏:

\def\mylist#1{\mylistA #1\and\and}
\def\mylistA#1\and{\ifx\and#1\and\else \and{#1}\expandafter\mylistA\fi}
\def\and#1{$\underline{\rm #1}$ }

\mylist{Element1 \and Element2}

编辑:Egreg 在此处的评论包含一个问题,即如何仅在项目之间打印分隔符。这很简单。我们只使用三行,无需额外的包,也没有任何麻烦:

\def\mylist#1{\def\mylistS{\def\mylistS{, }}\mylistA #1\and\and}
\def\mylistA#1\and{\ifx\and#1\and\else \and{#1}\expandafter\mylistA\fi}
\def\and#1{\mylistS $\underline{\rm #1}$}

\mylist{Element1 \and Element2}

编辑2:如果有人需要在最后两个项目之间打印另一个分隔符,那么他可以使用以下代码。当然,它稍微复杂一些:

\def\mylist#1{\def\mylistS{}\def\andA##1{\let\andA=\andB}\mylistA #1\and\and}
\def\mylistA#1\and{\ifx\and#1\and \and{}\else \and{#1}\expandafter\mylistA\fi}
\def\and#1{\ifx\mylistS\empty\else\andA{#1}\fi\mylistS \def\mylistS{$\underline{\rm #1}$}}
\def\andB#1{\ifx\and#1\and{ and }\else{, }\fi}

元素之间打印逗号,但最后两个元素之间打印单词“and”。

答案4

如果您不受限制物品的想法的约束,\and您可能想看看包裹commadodowith我最近在遇到类似问题时发现的包裹。

对于前者,你可以尝试一些类似的事情

    \usepackage{commado}
    % ...
    \newcommand{\myList}[2][\underline]{\doWithCSL{#1}{#2}}

并称之为

    \myList{Element1, Element2}

由于这不会在元素之间产生任何空间,因此以下添加将(几乎)重现上述示例

    \usepackage{commado}
    \usepackage{xspace}
    \newcommand{\myul}[1]{\underline{#1}\xspace}
    \newcommand{\myem}[1]{\emph{#1}\xspace}
    \newcommand{\myList}[2][\myul]{\doWithCSL{#1}{#2}}
    % ...
    \mylist{Element1, Element2}!

    \mylist[\myem]{Element1, Element2}!

(感叹号表示\xspace如果不需要的话,有助于抑制尾随空格)

所有软件包都是标准分发的一部分。

相关内容