我定义了一个命令\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
这不是对具体问题的回答,而是对主要问题的回答。
您有一个以下形式的数据库
\def\texti{Text for question 1} \def\textii{Text for question 2} ... \def\soli{Text for solution 1} \def\solii{Text for solution 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}