pgf 的 \foreach 宏

pgf 的 \foreach 宏

请问有没有办法关闭组范围\foreach?以下问题说明了我的困难。没有全局分配,目标就无法实现,但全局分配可能会把事情搞得太过分。

安德鲁·斯泰西:这是一个真正的问题。

\documentclass{article}
\usepackage{pgffor}
\begin{document}

\newcount\nra\newcount\nrb
\def\print{%
  \par{\tt\tabskip=20pt
    \halign to\hsize{##&##&##\cr
      \number\nra-\number\nrb:& \xa/\xb & \ya/\yb\cr
  }}%
}

\begingroup
\nrb=10
Value of `{\tt\string\nrb}' within the current group is \number\nrb.
\par\medskip
\xdef\savednrb{\the\nrb}
\foreach \xa\xb in {a1/a2,b1/b2,c1/c2,d1/d2}{%
  \global\advance\nra by1
  \nrb=0
  \foreach \ya\yb in {s1/s2,t1/t2,u1/u2,v1/v2}{%
    \global\advance\nrb by1
    \ifnum\nrb>1 \breakforeach\fi
    \print
  }%
}
\endgroup

\par\medskip
Value of `{\tt\string\nrb}' outside the latest group is \number\nrb, not \number\savednrb.

\end{document} 

答案1

这是我正在构建的解决方案卡托皮通包。在这个方案中,没有硬连线的计算本地范围。接受任意解析器,甚至活动解析器。距离完美的终点线还有一段路要走。尚未提供“评估”和“计数”等用户变量/键的规定。由于没有硬连线的本地组,我们不需要\foreach这里的“记住”变量。变量“记住”\foreach实际上应该读作“记住最后”。在目前的方案中,我们需要用以下形式的标记来完成参数n,...,m

\documentclass{article}
\usepackage{tikz}
\usepackage{catoptions}
\makeatletter
% \newforeach*[<options>]<holder-cmds>\in<list>\do{<callback>}
%
% The optional <options> include
%  1. Main list parser <parser>; its default value is comma (,).
%  2. Sub list parser <subparser>; its default value is slash (/).
%      <subparser> or <sub parser> separates the sublists, eg, slash
%      in the following list:
%      \x/\y/\z -> a/b/c, d/e/f, g/h/i
%  3. Other options as in pgf's \foreach (to be included).
%
% Both the main parser and sub parser can be active characters,
% unlike in pgf's \foreach.
%
% The optional star (*) suffix, when specified, implies that <listcmd>
% (a macro containing the list) is given in place of <list>.
%
% Any type of argument and delimiter is allowed in \newforeach.

\robust@def*\newforeach{\cpt@teststopt\cpt@foreach@a{}}
\robust@def*\cpt@foreach@a[#1]#2\in#3\do{%
  \ifnextcharTF\bgroup{%
    \cpt@foreach@c{#1}{#2}{#3}%
  }{%
    \cpt@foreach@b{#1}{#2}{#3}%
  }%
}
\robust@def*\cpt@foreach@b#1#2#3#4;{\cpt@foreach@c{#1}{#2}{#3}{#4}}
\robust@def*\cpt@foreach@c#1#2#3#4{%
  % Localize internal macros but not user callbacks:
  \begingroup
  \cpt@stchoose{cpt@st}{#3}\foreach@list\cpt@foreach@c
  \def\foreach@parser{,}%
  \def\foreach@subparser{/}%
  \def\foreach@normalize##1##2{%
    \ifblankTF{##2}{%
      \def\normalized@list{}%
    }{%
      \expandafter\csv@@normalize\expandafter[##1]{##2}%
    }%
  }%
  % Process the keys/variables:
  \def\foreach@split##1=##2=##3\@nil{%
    \csn@edef{foreach@\cptzapspaces{##1}}{\cpttrimspace{##2}}%
  }%
  \kv@@normalize{#1}%
  \expandafter\cptfor\normalized@list\dofor{%
    \foreach@split##1==\@nil
  }%
  % Normalize the given list for active subparser and spurious spaces:
  \cptexpandsecond\foreach@normalize
    {{\foreach@subparser}{\expandcsonce\foreach@list}}%
  \let\foreach@list\normalized@list
  % We need a scanner here, but user callbacks will not be rescanned:
  \def\foreach@rescan##1{%
    \begingroup
    \endlinechar\m@one\newlinechar\m@one
    \everyeof{\foreach@nil}%
    \def\reserved@a####1\foreach@nil{%
      \endgroup\edef##1{\unexpanded{####1}}%
    }%
    \expandafter\reserved@a\scantokens\expandafter{##1}%
  }%
  \def\ifforeach@subparser##1{%
    \expandafter\ifstrcmpTF\expandafter{\foreach@subparser}{##1}%
  }%
  % \foreach@holderlistb contains holders defined in terms of the
  % parameters of \csv@do; \foreach@holderlista is simply a comma list
  % of the holders:
  \@tempcnta\z@pt\def\foreach@holderlista{}%
  \def\foreach@holderlistb{}\def\foreach@paramlist{}%
  % Normalize holder-macro list for active subparsers and spurious
  % spaces:
  \foreach@normalize\foreach@subparser{#2}%
  \expandafter\cpttfor\normalized@list\dofor{%
    \ifforeach@subparser{##1}{%
      \ifnum\@tempcnta=\z@pt
        \cpt@err{First item of \noexpand\newforeach can't
          \MessageBreak be a delimiter}\@ehc
      \fi
      % Insert holder delimiter:
      \edef\foreach@paramlist{%
        \expandcsonce\foreach@paramlist\unexpanded{##1}%
      }%
    }{%
      \advance\@tempcnta\@ne
      \edef\foreach@holderlista{%
        \ifcsemptyTF\foreach@holderlista
          {}{\expandcsonce\foreach@holderlista,}%
        \unexpanded{##1}%
      }%
      \edef\foreach@holderlistb{%
        \expandcsonce\foreach@holderlistb
        \edef\unexpanded{##1}{%
          \noexpand\cpttrimspace{\cpt@hashchar\number\@tempcnta}%
        }%
      }%
      \edef\foreach@paramlist{%
        \expandcsonce\foreach@paramlist\cpt@hashchar\number\@tempcnta
      }%
    }%
  }%
  % Save holder macros #2 (eg, \x, \y, \z) so that \newforeach can later
  % restore their prior definitions:
  \cptexpandargonce{\pushfunctions\newforeach}%
    \foreach@holderlista\cpt@csvdepth
  \foreach@rescan\foreach@holderlistb
  \foreach@rescan\foreach@paramlist
  \let\foreach@nil\relax
  \def\elt{foreach@do@\romannumeral\cpt@csvdepth}%
  \cptexpanded{\endgroup
    \def\noexpandcsn\elt\expandcsonce\foreach@paramlist\foreach@nil{%
      \expandcsonce\foreach@holderlistb\unexpanded{#4}%
    }%
    \def\noexpand\csv@do####1{%
      \noexpandcsn\elt####1\foreach@nil
    }%
    \csv@@parse[\foreach@parser]{\expandcsonce\foreach@list}%
  }%
  % Restore holder macros to their pre-loop values:
  \popfunctions\newforeach\cpt@csvdepth
}
\newletcs\breaknewforeach\loopbreak
\makeatother

\begin{document}
% Examples:
\newcount\nra\newcount\nrb
% The parser is semicolon (;) in the outer loop; the subparser is slash (/).
\newforeach[parser=;,sub parser=/] \xa/\ya/\za \in
  a1/b1/c1; a2/b2/c2; a3/b3/c3 \do{%
  \advance\nra by1 \nrb=0
  % \xa, \ya, \za, etc, will be despaced (ie, spurious leading and
  % trailing spaces around their contents will be removed internally).
  % The parser is comma (,) in the inner loop; the subparser is bar (|).
  % The token 'parser={,}' below can be omitted, since comma is the
  % default parser:
  \newforeach[parser={,},sub parser=|] \xb|\yb|\zb \in
    s1|t1|u1, s2|t2|u2, s3|t3|u3 \do{%
    \advance\nrb by1
    \def\elt{cmda@\romannumeral\nra @\romannumeral\nrb}%
    \expandafter\edef\csname\elt\endcsname####1{%
      \xa\ya\za*####1*\xb\yb\zb
    }%
    \ifnum\nrb>1 \breaknewforeach\fi
    {\tt\expandafter\meaning\csname\elt\endcsname}\endgraf
  }%
}
\par\medskip
% TikZ example:
\begin{tikzpicture}[shading=ball]
\newforeach \x / \cola \in 0/red,1/green,2/blue,3/yellow\do{%
  \newforeach \y / \colb \in {0/red,1/green,2/blue,3/yellow}\do{%
    \shade[ball color=\cola!50!\colb] (\x,\y) circle (0.4cm);
  }%
}
\end{tikzpicture}

% Or
\begingroup
\catcode`\,=13 % active commas
\gdef\listb{0/red, 1/green, 2/blue, 3/yellow}
\endgroup

\tikz[shading=ball]
\newforeach \x/\cola \in 0/red,1/green,2/blue,3/yellow\do{%
  \newforeach* \y/\colb \in \listb\do{%
    \shade[ball color=\cola!50!\colb] (\x,\y) circle (0.4cm);
  }%
};

\begin{tikzpicture}[shading=ball]
% Exercise: why can't we use \tikz[shading=ball] here?
\newforeach[parser=;] \x/\cola \in 0/red; 1/green; 2/blue; 3/yellow\do{%
  \edef\cmdx{\x}%
  \foreach[remember=\y as \remy (initially 0)] \y/\colb in 
    {0/red, 1/green, 2/blue, 3/yellow}{%
    \edef\cmdy{\y}%
    \shade[ball color=\cola!50!\colb] (\x,\y) circle (0.4cm);
  }%
}
% \show\cmdx % defined
% \show\cmdy % undefined
\end{tikzpicture}

% Examining \foreach's variable 'remember':
\begin{tikzpicture}[shading=ball]
% \remx is remembered as \x only after the loop, hence only the last 
% value (3) is returned in \remx. \savedremx returns repeated entries of initial 
% assignment:
\foreach[remember=\x as \remx (initially 0)] \x / \cola in 
  {0/red,1/green,2/blue,3/yellow}{%
  \xdef\savedremx{\ifdefFT\savedremx{}{\ifcsemptyTF\savedremx{}{\savedremx,}}\remx}%
  \foreach \y / \colb in {0/red,1/green,2/blue,3/yellow}{%
    \shade[ball color=\cola!50!\colb] (\x,\y) circle (0.4cm);
  }%
}
%\show\remx
%\show\savedremx
\end{tikzpicture}
%\show\remx
\end{document}

在此处输入图片描述

在此处输入图片描述

相关内容