在循环中使用先前定义的命令会停止循环

在循环中使用先前定义的命令会停止循环

我定义了一个命令\mycommand,然后我想在循环中使用它,例如

\newcounter{myc}\setcounter{myc}{0}
\def\myloop#1{
    \loop
        \ifnum \themyc <#1
        \mycommand
        \stepcounter{myc}
    \repeat
}

好吧,我没有收到任何错误,但循环只运行了一次。如果我删除\mycommand并使用 LaTeX 的常规命令,那么它就会按预期工作。

这种行为的根源是什么?

完整代码如下。

\documentclass{amsart}
\usepackage{tikz}


\makeatletter
\def\prunelist#1{%
\expandafter\edef\csname pgfmath@randomlist@#1\endcsname
    {\the\numexpr\csname pgfmath@randomlist@#1\endcsname-1\relax}
\count@\pgfmath@randomtemp
\loop
    \expandafter\let
    \csname pgfmath@randomlist@#1@\the\count@\expandafter\endcsname
    \csname pgfmath@randomlist@#1@\the\numexpr\count@+1\relax\endcsname
    \ifnum\count@<\csname pgfmath@randomlist@#1\endcsname\relax
    \advance\count@\@ne
\repeat}


\def\declareromanlist#1#2#3{
\expandafter\xdef\csname pgfmath@randomlist@#1\endcsname{#3}
\count@#2\relax
\loop
    \expandafter\xdef
    \csname pgfmath@randomlist@#1@\the\count@\endcsname
    {\@roman\count@}
    \ifnum\count@<#3\relax
    \advance\count@\@ne
\repeat}


\makeatother

\pgfmathsetseed{12538}


\begin{document}

\def\texti{one}
\def\textii{two}
\def\textiii{three}

\declareromanlist{mylist}{1}{3}
\newcounter{num}
\setcounter{num}{0}

\newcommand{\mycommand}[1][\random]{
\stepcounter{num}
\pgfmathrandomitem\z{mylist}\edef\random{\z}\prunelist{mylist}
\expandafter\xdef\csname newtext\roman{num}\endcsname
{\expandafter\csname text#1\endcsname}
}


\newcounter{myc}

\def\myloop#1{%
\setcounter{myc}{0}
\loop  \ifnum\themyc <#1 \stepcounter{myc}
%\mycommand
check: \themyc
\repeat
}

\myloop{3}

\end{document}

如果我注释掉\mycommand,循环就会运行三次;如果我插入 \mycommand,则只运行一次。

答案1

新答案

由于编辑后的问题与原始问题无关......

\loop是一个基于纯 TeX 中的宏的简单宏,不能嵌套。据推测它在 pgf 代码的某个地方使用。添加分组级别可以解决这个问题:

\documentclass{amsart}
\usepackage{tikz}


\makeatletter
\def\prunelist#1{%
\expandafter\edef\csname pgfmath@randomlist@#1\endcsname
    {\the\numexpr\csname pgfmath@randomlist@#1\endcsname-1\relax}%
\count@\pgfmath@randomtemp 
\loop
\expandafter\let
\csname pgfmath@randomlist@#1@\the\count@\expandafter\endcsname
\csname pgfmath@randomlist@#1@\the\numexpr\count@+1\relax\endcsname
\ifnum\count@<\csname pgfmath@randomlist@#1\endcsname\relax
\advance\count@\@ne
\repeat}


\def\declareromanlist#1#2#3{%
\expandafter\xdef\csname pgfmath@randomlist@#1\endcsname{#3}%
\count@#2\relax
\loop
\expandafter\xdef
\csname pgfmath@randomlist@#1@\the\count@\endcsname
{\@roman\count@}
\ifnum\count@<#3\relax
\advance\count@\@ne
\repeat}
\makeatother 

\pgfmathsetseed{12538}


\begin{document}

\def\texti{one}
\def\textii{two}
\def\textiii{three}

\declareromanlist{mylist}{1}{3}
\newcounter{num}
\setcounter{num}{0}

\newcommand{\mycommand}[1][\random]{%
\stepcounter{num}%
\pgfmathrandomitem\z{mylist}\def\random{\z}\prunelist{mylist}%
\expandafter\xdef\csname newtext\roman{num}\endcsname
{\expandafter\csname text#1\endcsname}%
}


\newcounter{myc}

\def\myloop#1{%
\setcounter{myc}{0}
\loop  \ifnum\themyc <#1 \stepcounter{myc}%
{\mycommand}%
check: \themyc
\repeat
}

\myloop{3}


\end{document}

原始答案

您遗漏了什么\loop,但是它会产生错误还是不产生错误,这取决于命令的定义,除非您取消注释重新定义,否则不会产生错误。

\documentclass{article}

\begin{document}

\newcounter{myc}\setcounter{myc}{0}

\def\myloop#1{%
\loop
\ifnum \themyc <#1
\mycommand
\stepcounter{myc}%
\repeat
}


\newcommand\mycommand{ [a] }

%\renewcommand\mycommand{\newcommand\zzzz{x}}

\myloop{4}

\end{document}

答案2

这不是对具体问题的回答,而是对主要问题的回答。

  1. 您有一个以下形式的数据库

    \def\texti{Text for question 1}
    \def\textii{Text for question 2}
    ...
    \def\soli{Text for solution 1}
    \def\solii{Text for solution 2}
    ...
    
  2. 你想随机提取一些问题和相关答案,但不重复

以下宏\selectrandom接收要提取的问题数量作为参数,并构建以下形式的宏

\usetexti
\usetextii
...
\usesoli
\usesolii
...

这将扩展到所选问题和相关解决方案的文本。

在代码中,你会发现一个以

%%% Build the database, just for the example

这只是用模拟数据填充数据库。当然,您也可以\input{<database>}加载问题和答案。

\documentclass{article}
\usepackage{xparse}
\input{random}

\ExplSyntaxOn
% interface to random.tex
\cs_set_eq:NN \egreg_random_choose:Nnn \setrannum

%%% User level commands

\NewDocumentCommand{\selectrandom}{m}
 {% #1 is the number of choices to make
  \egreg_select_random:n { #1 }
 }

%%% Variables
% The random integer
\int_new:N \l_egreg_random_int

% A sequence for the available numbers
\seq_new:N \g_egreg_available_numbers_seq
% Populate the sequence
\int_step_inline:nnnn { 1 } { 1 } { 100 } % the number of available questions and answers
 { \seq_gput_right:Nn \g_egreg_available_numbers_seq { #1 } }

%%% Public functions
\cs_new_protected:Npn \egreg_select_random:n #1
 {
  % repeat the extraction #1 times
  \int_step_inline:nnnn { 1 } { 1 } { #1 } { \egreg_select_one_random:n { ##1 } }
 }

\cs_new_protected:Npn \egreg_select_one_random:n #1
 {
  % extract a random number among the available ones
  \egreg_random_choose:Nnn \l_egreg_random_int { 1 } { \seq_count:N \g_egreg_available_numbers_seq }
  % remove the selected number from the list
  \seq_gremove_all:Nf \g_egreg_available_numbers_seq { \int_to_arabic:n { \l_egreg_random_int } }
  % if the selected number is 42 and the current step is 3
  % make \usetextiii equivalent to \textxlii
  % and \usesoliii equivalent to \solxlii
  \tl_set_eq:cc
   { usetext \int_to_roman:n { #1 } }
   { text \int_to_roman:n { \l_egreg_random_int } }
  \tl_set_eq:cc
   { usesol \int_to_roman:n { #1 } }
   { sol \int_to_roman:n { \l_egreg_random_int } }
 }
\cs_generate_variant:Nn \seq_gremove_all:Nn { Nf }

%%% Build the database, just for the example
\int_step_inline:nnnn { 1 } { 1 } { 100 }
 {
  \tl_set:cn { text \int_to_roman:n { #1 } } { Text~for~question~#1 }
  \tl_set:cn { sol \int_to_roman:n { #1 } } { Text~for~solution~#1 }
 }

\ExplSyntaxOff

\begin{document}

\selectrandom{10}

\usetexti\par
\usetextii\par
\usetextiii\par
\usetextiv\par
\usetextv\par
\usetextvi\par
\usetextvii\par
\usetextviii\par
\usetextix\par
\usetextx\par

\bigskip

\usesoli\par
\usesolii\par
\usesoliii\par
\usesoliv\par
\usesolv\par
\usesolvi\par
\usesolvii\par
\usesolviii\par
\usesolix\par
\usesolx\par

\end{document}

在此处输入图片描述

相关内容