为 foreach 循环设置全局变量命令

为 foreach 循环设置全局变量命令

如何将变量定义设置为全局变量以在 eachfor 循环之外使用它?

\newcommand\Var[3]{ 
 \expandafter\edef\csname #1\Roman{#2}\endcsname{#3}
 }
\newcounter{count}
\foreach \i in {1,2,3,4,5,6,7,8,9}{
\stepcounter{count}
\Var{var}{count}{\Alph{count}}
}

\varII ???

答案1

欢迎!您的问题的答案是:使用\xdef而不是\edef,即

\documentclass{article}
\usepackage{pgffor}
\newcounter{count}
\newcommand\Var[3]{ 
 \expandafter\xdef\csname #1\Roman{#2}\endcsname{#3}
 }
\foreach \i in {1,2,3,4,5,6,7,8,9}{
\stepcounter{count}
\Var{var}{count}{\Alph{count}}
}
\begin{document}
\varIII
\end{document}

但是,您不需要将变量设为全局变量。相反,您可以使用内置函数\loop来实现这一点。

\documentclass{article}
\newcommand\Var[3]{ 
 \expandafter\edef\csname #1\Roman{#2}\endcsname{#3}
 }
\newcounter{count}
\setcounter{count}{0}
\loop
\stepcounter{count}
\Var{var}{count}{\Alph{count}}%
\ifnum\value{count}<10
\repeat
\begin{document}
\varIII
\end{document}

答案2

您可以使用 来实现xparse;我假设您的值不是连续的整数。我添加了一个可选数字来更改列表分隔符,以防您需要在值中使用逗号。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\setvariables}{mO{,}m}
 {% #1 = prefix for the variable name
  % #2 = separator (optional, default comma)
  % #3 list of values
  \hadi_setvariables:nnn { #1 } { #2 } { #3 }
 }

\cs_new_protected:Nn \hadi_setvariables:nnn
 {
  \seq_set_split:Nnn \l_tmpa_seq { #2 } { #3 }
  \seq_indexed_map_inline:Nn \l_tmpa_seq
   {% ##1 is the current index, ##2 is the current item
    \tl_set:cn { #1 \int_to_Roman:n { ##1 } } { ##2 }
   }
 }

\ExplSyntaxOff

\begin{document}

\setvariables{var}{1,2,3,9,5.2}

\varI \quad \varII \quad \varIII \quad \varIV \quad \varV

\setvariables{xyz}[;]{1;0.1;a,b}

\xyzI \quad \xyzII \quad \xyzIII

\end{document}

在此处输入图片描述

答案3

使用 pgffor/TikZ 时,\foreach每次迭代都在其自己的本地范围内进行。迭代中发生的非全局赋值(例如,就 而言\edef)仅限于该迭代的本地范围。

请注意,当使用 LaTeX 2ε 内核\@for而不是 pgffor/TikZ 内核时\foreach,迭代不会在新的局部范围内进行。因此,使用 LaTeX 2ε 内核时,\@for您不需要\xdef但可以使用\edef— 可以是这样的:

\documentclass{article}

\makeatletter
\newcounter{count}
\newcommand\Var[3]{%
  \expandafter\edef\csname #1\Roman{#2}\endcsname{#3}%
}%
\setcounter{count}{0}%
\@for\i:=0001,0010,0011,0100,0101,0110,0111,1000,1001\do{%
  \stepcounter{count}%
  \Var{var}{count}{Alphabetic: \Alph{count}--Binary: \i}%
}%
\makeatother

\begin{document}
\noindent
\verb|\varI|: \varI \\
\verb|\varII|: \varII \\
\verb|\varIII|: \varIII \\
\verb|\varIV|: \varIV \\
\verb|\varV|: \varV \\
\verb|\varVI|: \varVI \\
\verb|\varVII|: \varVII \\
\verb|\varVIII|: \varVIII \\
\verb|\varIX|: \varIX \\
\end{document}

在此处输入图片描述


您使用和。\Roman{⟨LaTeX counter⟩}\Alph{⟨LaTeX counter⟩}

如果您改用和,则可以不用计数寄存器。\@Roman{⟨TeX number quantity⟩}\@Alph{⟨TeX number quantity⟩}

如果没有可用的 ε-TeX 扩展,您可能需要实现一个可扩展增量例程:

\documentclass{article}

\makeatletter
%------------------------------------------------------------------------------
% Expandable incrementing of natural number formed by a sequence of
% explicit catcode-12-character-tokens-from-the-set {0,1,2,3,4,5,6,7,8,9}
%..............................................................................
% \Increment{<natural number k as sequence of explicit catcode-12-character-
%             tokens from the set 0123456789>}
% ->
% <natural number (k+1) as sequence of explicit catcode-12-character-tokens
%  from the set 0123456789>
% In expansion-contexts the result is delivered after two expansion-steps/is 
% obtained by "hitting" \Increment with \expandafter twice.
%------------------------------------------------------------------------------
\newcommand\Increment[1]{%
  \romannumeral0%
  \UD@IncrementReverse{\UD@IncrementFork{}}{\relax}{}#1\relax
}%
\newcommand\UD@IncrementReverse[4]{%
  \ifx\relax#4%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {#1#3#2}{\UD@IncrementReverse{#1}{#2}{#4#3}}%
}%
\@ifdefinable\UD@IncrementSelect{%
  \long\def\UD@IncrementSelect#10123456789\relax#2#3!!{#2}%
}%
\newcommand\UD@IncrementFork[2]{%
  \UD@IncrementSelect
  #2123456789\relax{\UD@IncrementReverse{ }{}{}#11}%
  0#223456789\relax{\UD@IncrementReverse{ }{}{}#12}%
  01#23456789\relax{\UD@IncrementReverse{ }{}{}#13}%
  012#2456789\relax{\UD@IncrementReverse{ }{}{}#14}%
  0123#256789\relax{\UD@IncrementReverse{ }{}{}#15}%
  01234#26789\relax{\UD@IncrementReverse{ }{}{}#16}%
  012345#2789\relax{\UD@IncrementReverse{ }{}{}#17}%
  0123456#289\relax{\UD@IncrementReverse{ }{}{}#18}%
  01234567#29\relax{\UD@IncrementReverse{ }{}{}#19}%
  012345678#2\relax{\UD@IncrementFork{#10}}%
  0123456789#2{\UD@IncrementReverse{ }{}{}#11\relax}%
  0123456789\relax{\UD@IncrementReverse{ }{}{}#11#2}%
  !!%
}%
%------------------------------------------------------------------------------
\newcommand\VarLoop[4]{%
  \ifnum#2<\expandafter\@firstofone\expandafter{\number#1} %
    \expandafter\@gobble
  \else
    \expandafter\@firstofone
  \fi{%
    \expandafter\edef\csname#3\@Roman{#1}\endcsname{#4{#1}}%
    %\expandafter\show\csname#3\@Roman{#1}\endcsname%
    \expandafter\expandafter\expandafter\VarLoop
    \expandafter\expandafter\expandafter{\Increment{#1}}{#2}{#3}{#4}%
  }%
}%
%------------------------------------------------------------------------------
\VarLoop{1}{9}{var}{\@Alph}
%------------------------------------------------------------------------------    
\makeatother

\begin{document}
\noindent
\verb|\varI|: \varI \\
\verb|\varII|: \varII \\
\verb|\varIII|: \varIII \\
\verb|\varIV|: \varIV \\
\verb|\varV|: \varV \\
\verb|\varVI|: \varVI \\
\verb|\varVII|: \varVII \\
\verb|\varVIII|: \varVIII \\
\verb|\varIX|: \varIX \\
\end{document}

在此处输入图片描述

如果有 ε-TeX 扩展可用,您可以使用\number\numexpr...\relax可扩展增量:

\documentclass{article}

\makeatletter
%------------------------------------------------------------------------------
\newcommand\VarLoop[4]{%
  \ifnum#2<\expandafter\@firstofone\expandafter{\number#1} %
    \expandafter\@gobble
  \else
    \expandafter\@firstofone
  \fi{%
    \expandafter\edef\csname#3\@Roman{#1}\endcsname{#4{#1}}%
    %\expandafter\show\csname#3\@Roman{#1}\endcsname%
    \expandafter\VarLoop
    \expandafter{\number\numexpr\number#1+1\relax}{#2}{#3}{#4}%
  }%
}%
%------------------------------------------------------------------------------
\VarLoop{1}{9}{var}{\@Alph}
%------------------------------------------------------------------------------    
\makeatother

\begin{document}
\noindent
\verb|\varI|: \varI \\
\verb|\varII|: \varII \\
\verb|\varIII|: \varIII \\
\verb|\varIV|: \varIV \\
\verb|\varV|: \varV \\
\verb|\varVI|: \varVI \\
\verb|\varVII|: \varVII \\
\verb|\varVIII|: \varVIII \\
\verb|\varIX|: \varIX \\
\end{document}

在此处输入图片描述


顺便一提:

似乎您使用它\Roman来将数字转换为类别代码 11(字母)的字符标记,这些字符标记可以出现在控制字标记的名称中,如\varI\varII等。

您是否知道\csname..\endcsname可以通过 (La)TeX 构造名称包含数字的标记?

例如,

\csname varI\endcsname产生控制字标记\varI

同样地

\csname var1\endcsname产生控制字标记\var1

您不能\var1直接在 .tex 输入文件中输入,因为 (La)TeX 的读取和标记设备会将其标记成 和。\varcontrol word token1explicit character token of category code 12(other)

\csname var1\endcsname读取和标记如下:

  1. \csnamecontrol word token
  2. vexplicit character token of category code 11(letter)
  3. aexplicit character token of category code 11(letter)
  4. rexplicit character token of category code 11(letter)
  5. 1explicit character token of category code 12(other)
  6. \endcsnamecontrol word token

在下一个阶段,在扩展事物的时候,组成 -表达式 的标记\csname..\endcsname会被扩展,扩展的结果\csname...就是标记。\var1control word token

(La)TeX 中有一个很好的特殊功能,称为#{-notation,它允许您定义最后一个参数以 分隔的宏{

您可以定义一个命令

\name⟨stuff without braces⟩{⟨ControlSequenceName⟩}

经过两个扩展步骤后,结果如下:

⟨stuff without braces⟩\ControlSequenceName

你可以像这样使用它:

\name{Var23}\Var23
\name\newcommand{Var23}...\newcommand\Var23...
\name\global\long\def{Var23}...\global\long\def\Var23...
\name\show{Var23}\show\Var23
\name\meaning{Var23}\meaning\Var23
\name\name\let{Var23}={Var24}\name\let\Var23={Var24}\let\Var23=\Var24

\documentclass{article}

\newcounter{scratchcounter}

% Let's define the \name-macro:

\makeatletter
\newcommand\exchange[2]{#2#1}%
\@ifdefinable\name{\long\def\name#1#{\romannumeral0\innername{#1}}}%
\newcommand\innername[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\makeatother

% Let's define "variables/macros" \var1..\var9 in a loop:

\setcounter{scratchcounter}{0}%
\loop
  \stepcounter{scratchcounter}%
  \name\name{@ifdefinable}{var\number\value{scratchcounter}}{%
    \name\edef{var\number\value{scratchcounter}}{\Alph{scratchcounter}}%
  }%
\ifnum\value{scratchcounter}<9
\repeat

% Let's define the macro \foo45/c-;/bar

\name\newcommand*{foo45/c-;/bar}{This is a macro with a weird name.}

\parindent=0ex

\begin{document}
\verb|\name{var1}|: $\to$ \texttt{\name\string{var1}} $\to$ \name{var1} \\
\verb|\name{var2}|: $\to$ \texttt{\name\string{var2}} $\to$ \name{var2} \\
\verb|\name{var3}|: $\to$ \texttt{\name\string{var3}} $\to$ \name{var3} \\
\verb|\name{var4}|: $\to$ \texttt{\name\string{var4}} $\to$ \name{var4} \\
\verb|\name{var5}|: $\to$ \texttt{\name\string{var5}} $\to$ \name{var5} \\
\verb|\name{var6}|: $\to$ \texttt{\name\string{var6}} $\to$ \name{var6} \\
\verb|\name{var7}|: $\to$ \texttt{\name\string{var7}} $\to$ \name{var7} \\
\verb|\name{var8}|: $\to$ \texttt{\name\string{var8}} $\to$ \name{var8} \\
\verb|\name{var9}|: $\to$ \texttt{\name\string{var9}} $\to$ \name{var9} \\
\verb|\name{foo45/c-;/bar}|: $\to$ \texttt{\name\string{foo45/c-;/bar}}  $\to$ \name{foo45/c-;/bar}

\hrulefill\null

Now let's redefine \verb|\var8|:

\verb|\name\renewcommand{var8}[1]{Now we have a macro which processes an argument: #1}|\\
$\to$\\
\verb|\renewcommand\var8[1]{Now we have a macro which processes an argument: #1}|\\
\name\renewcommand{var8}[1]{Now we have a macro which processes an argument: #1}

\verb|\name\string{var8}: \name\meaning{var8}| yields:

\begingroup
\ttfamily\frenchspacing
\hbox{%
\name\string{var8}: \name\meaning{var8}%
}%
\endgroup
\end{document}

在此处输入图片描述

相关内容