从 listofitems 包处理的列表中定义宏

从 listofitems 包处理的列表中定义宏

我想用不同的颜色区分不同代理的控制变量,以便我的学生更容易阅读示例。为此,我想编写一个宏\definevar{x,y;z},可以在每个示例的开头调用它,\var在分号前定义为{\color{player1} var},在分号后定义为{\color{player2} var}。我发现在这个答案中如何对单个变量执行此操作,但令人惊讶的是,这种方法并没有listofitems以直接的方式扩展到包处理的列表。

在下面的代码中,\defvar对于单个变量来说,效果很好,但不知何故\definevar没有定义变量。如果我\foreachpgfplot's替换\pgfplotsforeachungrouped,它会定义变量,但将它们全部初始化为最后一个输入变量。

\documentclass{article}
\usepackage{xcolor, pgffor, listofitems}

\colorlet{player1}{blue}
\colorlet{player2}{red}

\newcommand{\defvar}[2]{
    \expandafter\def\csname #2\endcsname{{\color{player#1} #2}}
}

\newcommand{\definevar}[1]{
    \setsepchar{;/,}%
    \greadlist*\varlist{#1}%
    \foreach \pl in {1, ..., \varlistlen} {%
        \foreachitem \i \in \varlist[\pl] {%
            \defvar{\pl}{\i}%
        }%
    }%
}

\begin{document}

\defvar{1}{x}
\defvar{2}{y}
$\x + \y = 1$.

\definevar{x, y; z}
$\x + \y = \z$.

\end{document}

答案1

几个问题:

  1. \defvar需要使用全局\gdef而不是\def,因为它是在的循环组内部调用的\definevar

  2. \pl\i需要先展开一次才能用于调用\defvar。如果没有这个, 会\defvar保留文字\pl和,\i而不是使用您想要的替换文本。

MWE 修复了:

\documentclass{article}
\usepackage{xcolor, pgffor, listofitems}

\colorlet{player1}{blue}
\colorlet{player2}{red}

\newcommand{\defvar}[2]{
    \expandafter\gdef\csname #2\endcsname{{\color{player#1} #2}}
}

\newcommand{\definevar}[1]{
    \setsepchar{;/,}%
    \greadlist*\varlist{#1}%
    \foreach \pl in {1, ..., \varlistlen} {%
        \foreachitem \i \in \varlist[\pl] {%
            \def\tmp{\expandafter\defvar\expandafter{\pl}}%
            \expandafter\tmp\expandafter{\i}%
        }%
    }%
}

\begin{document}

\defvar{1}{x}
\defvar{2}{y}
$\x + \y = 1$.

\definevar{x, y; z}
$\x + \y = \z$.

\end{document}

在此处输入图片描述

实现相同目标的另一种方法是使用\xdefinside of\defvar而不是 of \gdef(只要您\noexpand使用\color)。这样,在 内部\definevar,您可以恢复到更简单的语法,而不必担心扩展。

\documentclass{article}
\usepackage{xcolor, pgffor, listofitems}

\colorlet{player1}{blue}
\colorlet{player2}{red}

\newcommand{\defvar}[2]{
    \expandafter\xdef\csname #2\endcsname{{\noexpand\color{player#1} #2}}
}

\newcommand{\definevar}[1]{
    \setsepchar{;/,}%
    \greadlist*\varlist{#1}%
    \foreach \pl in {1, ..., \varlistlen} {%
        \foreachitem \i \in \varlist[\pl] {%
            \defvar{\pl}{\i}%
        }%
    }%
}

\begin{document}

\defvar{1}{x}
\defvar{2}{y}
$\x + \y = 1$.

\definevar{x, y; z}
$\x + \y = \z$.

\end{document}

答案2

您可以使用expl3,因此您不需要临时宏。

首先将参数\definevar以分号分割成几部分,然后检查每一部分,根据部分编号生成颜色变量,您只需定义任意多种颜色即可playern如你需要。

\documentclass{article}
\usepackage{xcolor}

\colorlet{player1}{blue}
\colorlet{player2}{red}
\colorlet{player3}{green!60!blue}

\ExplSyntaxOn

\NewDocumentCommand{\definevar}{m}
 {
  \seq_set_split:Nnn \l_tmpa_seq { ; } { #1 }
  \seq_map_indexed_inline:Nn \l_tmpa_seq
   {
    \clist_map_inline:nn { ##2 }
     {
      \cs_set_protected:cpn { ####1 } { \textcolor{player##1}{####1} }
     }
   }
 }

\ExplSyntaxOff

\begin{document}

$\definevar{x;y}\x + \y = 1$.

$\definevar{x,y;z;t}\x+\y=\z-\t$.

\end{document}

在此处输入图片描述

您可能还会考虑以下事项:

\documentclass{article}
\usepackage{xcolor}

\colorlet{player1}{blue}
\colorlet{player2}{red}
\colorlet{player3}{green!60!blue}

\ExplSyntaxOn

\NewDocumentCommand{\definevar}{m}
 {
  \seq_set_split:Nnn \l_tmpa_seq { ; } { #1 }
  \seq_map_indexed_inline:Nn \l_tmpa_seq
   {
    \clist_map_inline:nn { ##2 }
     {
      \cs_set_protected:cx { __olafsson_var_####1: }
       {
        \exp_not:N \textcolor{player##1}{\mathchar\the\mathcode`####1}
       }
      \char_set_active_eq:Nc ####1 { __olafsson_var_####1: }
      \mathcode `####1 = "8000 \scan_stop:
     }
   }
 }

\ExplSyntaxOff

\begin{document}

$\definevar{x;y} x + y = 1$.

$\definevar{x,y;z;t} x + y = z - t$.

\end{document}

产生相同的输出。

相关内容