通过多次扩展进行宏连接并保护一些标记?

通过多次扩展进行宏连接并保护一些标记?

在下面的 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) }; .

相关内容