在下面的 MWE 中,我想通过附加命令\doPlotCoords
从头开始创建一个宏:\addplot
\documentclass{article}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{adjustbox}
\usepackage{tikz}
\usetikzlibrary{pgfplots.groupplots}
\usetikzlibrary{shapes}
\usetikzlibrary{positioning}
\usetikzlibrary{decorations.pathreplacing}
\xdef\doPlotCoords{}
\foreach \r in {0,1,...,10}{%
\xdef\tempCoords{} %
\foreach \c in {0,1,...,10}{ %
\xdef\tempCoords{\tempCoords (\r,\c)\space}
} % end \foreach \c
% just \xdef concatenating gives "! Undefined control sequence." for \addplot; use \protected@edef
% \xdef\doPlotCoords{ \doPlotCoords
% \noexpand\addplot+[color=blue,mark=*,mark options={blue},] coordinates{ \tempCoords };}
% with "\protected@xdef", I get "! You can't use a prefix with `the character @'.":
\makeatletter %
\protected@xdef\doPlotCoords{ \doPlotCoords
\protect\addplot+[color=blue,mark=*,mark options={blue},] coordinates{ \tempCoords };}
\makeatother
} % end \foreach \r
\begin{document}
\show\doPlotCoords
\end{document}
最后,我希望\doPlotCoords
宏包含:
\addplot+[color=blue,mark=*,mark options={blue},] coordinates{ (0,0) (0,1) ... };
\addplot+[color=blue,mark=*,mark options={blue},] coordinates{ (1,0) (1,1) ... };
...
...所以我可以将其用作\doPlotCoords
“子程序”来执行所有这些\addplot
;但是,目前它失败了:
! You can't use a prefix with `the character @'.
<to be read again>
@
l.26 }
% end \foreach \r
我认为主要问题是:在第一个 时\xdef
,\protect
/\noexpand
可能会被遵守;但在连接时, 已经\doPlotCoords
包含\addplot
,因此当\xdef
试图扩展时\doPlotCoords
,它也会扩展\addplot
内部。但我真的不明白“您不能使用带有字符 @ 的前缀。”应该指什么,当使用时\protected@xdef
(通过以下方式获得最小 \protected@edef 示例)。
那么,如何使用\edef\mymacro{\mymacro something else}
类型连接构建宏,以便在多次运行\mymacro
时不会扩展内部受保护的标记?(我认为这种“多次”可能证明将这种方法称为“递归宏连接”;但我不确定,因为这不是函数调用本身的“真正”递归......)\edef
\mymacro
答案1
您遇到的问题类似于以下最小示例:
\documentclass{article}
\newcommand{\zz}[1]{%
\makeatletter%
\protected@edef\zzz{#1}%
\makeatother%
}
\begin{document}
abc\zz{zz}
\end{document}
你尝试在宏编程中保持简洁,使用\makeatletter
...\makeatother
一对仅在必要时才使用。在这种情况下,只需使用符号@
-围绕宏\protected@edef
即可。但是,当你宣布的定义\zz
,其替换文本(括号组内的所有内容)的类别代码已设置。也就是说,\makeatletter
...对对正确解释中\makeatother
的 没有任何影响。@
\protected@edef
解决方案是使用\makeatletter
...\makeatother
对外部定义:
\documentclass{article}
\makeatletter%
\newcommand{\zz}[1]{%
\protected@edef\zzz{#1}%
}
\makeatother%
\begin{document}
abc\zz{zz}
\end{document}
您创建的循环也是如此\foreach
。它们本质上也只是接受参数以界定范围的宏。因此,一旦读取这些参数(作为一个整体),类别代码更改就不会对其内容产生影响。将\makeatletter
...\makeatother
对外部这最外层(最低)组(\foreach
在您的情况下为了@
正确使用类似宏:
\makeatletter
\foreach ... {
...
\foreach ... {
...
}
...
}
\makeatother
答案2
您不能\makeatletter
在另一个命令的参数中使用(出于同样的原因,您不能\verb
在那里使用,但无论如何您实际上并不需要@
这里的命令:
\documentclass{article}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{adjustbox}
\usepackage{tikz}
\usetikzlibrary{pgfplots.groupplots}
\usetikzlibrary{shapes}
\usetikzlibrary{positioning}
\usetikzlibrary{decorations.pathreplacing}
\xdef\doPlotCoords{}
{\let\addplot\relax
\foreach \r in {0,1,...,10}{%
\xdef\tempCoords{}%
\foreach \c in {0,1,...,10}{%
\xdef\tempCoords{\tempCoords (\r,\c)\space}
}
\xdef\doPlotCoords{\doPlotCoords
\addplot+[color=blue,mark=*,mark options={blue},] coordinates{ \tempCoords };}
}% end \foreach \r
}
\begin{document}
\show\doPlotCoords
\end{document}
答案3
您可能会喜欢一个expl3
实现。宏\dosteps
是包装器\int_step_inline:nnnn
;语法是
\dostep{<initial>}[<step>]{<final>}{<code>}
其中步骤是可选的(默认为 1)。在 中<code>
,当前值可用作#1
。如果\dosteps
在 内调用a <code>
,则对于内部循环,当前值可用作##1
(依此类推,将 的数量加倍#
)。
该宏\appendto
将第二个参数附加到作为第一个参数给出的无参数宏;*
-variant 完成扩展。为了避免使用\noexpand\addplot
,我定义了一个\paddplot
本质上相同但在扩展下受保护的宏。
\documentclass{article}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{adjustbox}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{pgfplots.groupplots}
\usetikzlibrary{shapes}
\usetikzlibrary{positioning}
\usetikzlibrary{decorations.pathreplacing}
\ExplSyntaxOn
\NewDocumentCommand{\dosteps}{mO{1}mm}
{%#1=start, #2=step (default 1), #3=end, #4=code
\int_step_inline:nnnn {#1}{#2}{#3}{#4}
}
\NewDocumentCommand{\appendto}{smm}
{%#1=*, #2=token list, #3=code
\IfBooleanTF{#1}{\tl_put_right:Nx}{\tl_put_right:Nn} #2 { #3 }
}
\ExplSyntaxOff
\newcommand\tempCoords{} % initialize
\newcommand\doPlotCoords{}
\NewDocumentCommand{\paddplot}{}{\addplot}% protected version of \addplot
\dosteps{0}{10}{%
\renewcommand{\tempCoords}{}% reinitialize
\dosteps{0}{10}{%
\appendto\tempCoords{(#1,##1) }% #1 is the outer cycle, ##1 the inner one
}
\appendto*\doPlotCoords{%
\paddplot+[color=blue,mark=*,mark options={blue},] coordinates { \tempCoords };
}%
}
\begin{document}
\show\doPlotCoords
\end{document}
这是最终命令在终端上的输出\show
:
> \doPlotCoords=macro:
->\addplot +[color=blue,mark=*,mark options={blue},] coordinates { (0,0) (0,1)
(0,2) (0,3) (0,4) (0,5) (0,6) (0,7) (0,8) (0,9) (0,10) }; \addplot +[color=blue
,mark=*,mark options={blue},] coordinates { (1,0) (1,1) (1,2) (1,3) (1,4) (1,5)
(1,6) (1,7) (1,8) (1,9) (1,10) }; \addplot +[color=blue,mark=*,mark options={b
lue},] coordinates { (2,0) (2,1) (2,2) (2,3) (2,4) (2,5) (2,6) (2,7) (2,8) (2,9
) (2,10) }; \addplot +[color=blue,mark=*,mark options={blue},] coordinates { (3
,0) (3,1) (3,2) (3,3) (3,4) (3,5) (3,6) (3,7) (3,8) (3,9) (3,10) }; \addplot +[
color=blue,mark=*,mark options={blue},] coordinates { (4,0) (4,1) (4,2) (4,3) (
4,4) (4,5) (4,6) (4,7) (4,8) (4,9) (4,10) }; \addplot +[color=blue,mark=*,mark
options={blue},] coordinates { (5,0) (5,1) (5,2) (5,3) (5,4) (5,5) (5,6) (5,7)
(5,8) (5,9) (5,10) }; \addplot +[color=blue,mark=*,mark options={blue},] coordi
nates { (6,0) (6,1) (6,2) (6,3) (6,4) (6,5) (6,6) (6,7) (6,8) (6,9) (6,10) }; \
addplot +[color=blue,mark=*,mark options={blue},] coordinates { (7,0) (7,1) (7,
2) (7,3) (7,4) (7,5) (7,6) (7,7) (7,8) (7,9) (7,10) }; \addplot +[color=blue,ma
rk=*,mark options={blue},] coordinates { (8,0) (8,1) (8,2) (8,3) (8,4) (8,5) (8
,6) (8,7) (8,8) (8,9) (8,10) }; \addplot +[color=blue,mark=*,mark options={blue
},] coordinates { (9,0) (9,1) (9,2) (9,3) (9,4) (9,5) (9,6) (9,7) (9,8) (9,9) (
9,10) }; \addplot +[color=blue,mark=*,mark options={blue},] coordinates { (10,0
) (10,1) (10,2) (10,3) (10,4) (10,5) (10,6) (10,7) (10,8) (10,9) (10,10) }; .