使用不同输入参数的读取命令

使用不同输入参数的读取命令

出于好奇,我想定义一个如下所示的 LaTeX 命令:

\newcommand{\trigger}{out1,out2,...,outn}

具有一个相当奇怪的功能(至少我在其他地方找不到类似的东西):

首先,参数的数量out1,out2,...等都是变量。然后,每次\trigger在文档内容中使用该命令时,都会产生不同的细绳打印:首先out1,然后out2等,最后outnoutn打印后,整个过程应重置,以便下一个细绳还会再来out1的。

所以我遇到的第一个问题是创建一个可以读取逗号分隔列表的命令{},第二个问题是每次调用新定义的命令时如何仅打印其中一个。

答案1

之前的答案没有错,但这是另一个

在此处输入图片描述

\documentclass{article}

\newcommand{\triggerlist}{out1,out2,...,outn}
\def\trigger{\expandafter\xtrigger\triggerlist\xtrigger}
\def\xtrigger#1,#2\xtrigger{#1\def\triggerlist{#2,#1}}

\begin{document}

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\end{document}

答案2

使用 expl3 非常简单:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newsetcommand}{mm}
  {
   \seq_new:c { g_setcommand_ \cs_to_str:N #1 _seq }
   \seq_gset_split:cnn { g_setcommand_ \cs_to_str:N #1 _seq } {,} {#2}
   \cs_new:Npn #1
     {
      \seq_gpop_left:cN { g_setcommand_ \cs_to_str:N #1 _seq } \l_setcommand_temp_tl
      \seq_gput_right:cV { g_setcommand_ \cs_to_str:N #1 _seq } \l_setcommand_temp_tl
      \tl_use:N \l_setcommand_temp_tl
     }
  }
\tl_new:N \l_setcommand_temp_tl
\cs_generate_variant:Nn \seq_gset_split:Nnn { c }
\ExplSyntaxOff

\newsetcommand{\trigger}{out1,out2,out3,out4}

\begin{document}

\trigger

\trigger

\trigger

\trigger

\trigger

\end{document}

您会看到,\newsetcommand定义了一个新的宏,该宏扩展到列表的连续元素,并且可以定义尽可能多的相同类型的命令。

输出如下:

在此处输入图片描述


怎么运行的

\newsetcommand{\trigger}{<list>}定义

  1. 一个新的序列,名为\g_setcommand_trigger_seq,包含由逗号分隔的有序列表<list>

  2. 一个新的宏\trigger,每次调用时都会从关联序列中弹出最左边的元素,将其添加到序列的右侧并打印出来。

由于弹出的元素被添加回到序列的另一端,因此当打印最后一个原始元素时,下一个将再次成为第一个。


“经典”实现

\makeatletter
\newcommand{\newsetcommand}[2]{%
  \toks@{}%
  \@for\next:=#2\do{%
    \toks@=\expandafter{\the\expandafter\toks@\expandafter{\next}}%
  }
  \expandafter\gdef\csname setcommand\string#1\expandafter\endcsname\expandafter{\the\toks@}%
  \edef#1{\noexpand\@usecommand{\string#1}}%
}
\def\@usecommand#1{%
  \expandafter\expandafter\expandafter\@@usecommand\csname setcommand#1\endcsname\@nil{#1}\@nil}
\def\@@usecommand#1#2\@nil#3\@nil{%
  #1%
  \expandafter\gdef\csname setcommand#3\endcsname{#2{#1}}%
}
\makeatother

语法与以前相同。

编辑

感谢大卫卡莱尔的回答,这可以简化:

\makeatletter
\newcommand{\newsetcommand}[2]{%
  \global\@namedef{@setcommand\string#1}{#2}%
  \edef#1{\noexpand\@usecommand{\string#1}}%
}
\def\@usecommand#1{%
  \expandafter\expandafter\expandafter\@@usecommand\csname @setcommand#1\endcsname\@nil#1\@nil
}
\def\@@usecommand#1,#2\@nil#3\@nil{%
  \global\@namedef{@setcommand#3}{#2,#1}%
}
\makeatother

答案3

我的卑微​​尝试etoolbox,感谢Leo Liu 的回答。我使用\csdef\csuse来存储和使用值,并\DeclareListParser使用 来遍历逗号分隔列表中的项目。最后,该intcalc包提供了模数功能。

\documentclass{article}

\usepackage{etoolbox}
\usepackage{intcalc}

\DeclareListParser*{\myforeach}{,}

\newcounter{helpercounter}
\newcommand{\savethistext}[1]{%
\stepcounter{helpercounter}%
\csdef{triggerval\thehelpercounter}{#1}}

\newcounter{progresscounter}
\newcommand{\trigger}[1]{%
\setcounter{progresscounter}{\intcalcMod{\value{progresscounter} + 1}{\value{helpercounter} + 1}}%
\csuse{triggerval\theprogresscounter}\par%
}

\myforeach{\savethistext}{out1, out2, out3, out4}

\begin{document}

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\end{document}

输出

答案4

以下是使用高级 ConTeXt 特征的实现:countersconversion

\defineconversion[trigger][out1, out2, out3, out4]
\definestructurecounter[trigger][numberconversion=trigger]
\setstructurecounter[trigger]{0}

\def\trigger%
    {\incrementstructurecounter[trigger]%
     \convertedstructurecounter[trigger]}

\starttext
\startlines
\trigger
\trigger
\trigger
\trigger
\trigger
\stoplines
\stoptext

相关内容