我想用不同的颜色区分不同代理的控制变量,以便我的学生更容易阅读示例。为此,我想编写一个宏\definevar{x,y;z}
,可以在每个示例的开头调用它,\var
在分号前定义为{\color{player1} var}
,在分号后定义为{\color{player2} var}
。我发现在这个答案中如何对单个变量执行此操作,但令人惊讶的是,这种方法并没有listofitems
以直接的方式扩展到包处理的列表。
在下面的代码中,\defvar
对于单个变量来说,效果很好,但不知何故\definevar
没有定义变量。如果我\foreach
用pgfplot
'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
几个问题:
\defvar
需要使用全局\gdef
而不是\def
,因为它是在的循环组内部调用的\definevar
。\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}
实现相同目标的另一种方法是使用\xdef
inside 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
以分号分割成几部分,然后检查每一部分,根据部分编号生成颜色变量,您只需定义任意多种颜色即可player
n如你需要。
\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}
产生相同的输出。