我编写了以下宏,打印出用逗号分隔的一系列数字:
\newcount\tmpnum
\def\range#1#2#3{\tmpnum=#2
\loop\the\tmpnum\advance\tmpnum by #1
\ifnum\tmpnum<#3,\repeat,
}
例如,\range{2}{3}{10}
扩展为3,5,7,9,
。
我想将此扩展存储到宏中\therange
。我尝试的是:
\edef\therange{\range{2}{3}{10}}
% Should be the same as
% \def\therange{3,5,7,9,}
但我收到错误消息。为什么?如何实现我的目标?
答案1
\def\range#1#2#3{\altrange{#2}{#3}{#1}}
\def\altrange#1#2#3{\ifnum #1<\numexpr 1+#2\relax#1,\expandafter
\altrange\expandafter{\the\numexpr#1+#3\relax}{#2}{#3}\fi}
\edef\therange{\range{2}{3}{10}}
\edef\z{\range{3}{3}{15}}
The range is \therange\ while z is \z
\bye
如果有人想争论我是否用未解决的\fi
s 构建堆栈,直到最后(这只能成为非常大的列表的一个因素),那么人们可以玩“自由-\fi
我从 David 那里学到的“Free- -Fo'-Fun”游戏(尝试消除递归过程中的堆栈溢出(字母冒泡排序器)):
\def\range#1#2#3{\ifx11\altrange{#2}{#3}{#1}\fi}
\def\altrange#1#2#3\fi{\fi\ifnum #1<\numexpr 1+#2\relax#1,\expandafter
\altrange\expandafter{\the\numexpr#1+#3\relax}{#2}#3\fi}
\edef\therange{\range{2}{3}{10}}
\edef\z{\range{3}{3}{15}}
The range is \therange\ while z is \z
\bye
答案2
其他答案已经展示了如何做到这一点,我想解释一下你的方法为什么会失败。
只有一些 TeX 基元纯粹通过扩展工作 - 也就是说它们可以在 或类似 内实现其结果\edef
。\message
特别是,没有什么
- 执行任务
- 有排版吗
通过扩展来实现。在普通 TeX 中的定义\loop
使用赋值,因此不能在这样的上下文中使用。有几种方法可以设置没有赋值的循环,如其他答案所示。
我注意到你正在使用 LuaTeX:重要的是要注意 Lua 级别的分配是允许,因此如果你用 Lua 编写代码,‘规则会有所不同’。
答案3
该\edef
命令不执行分配并且您的循环充满了分配。
有了luatex
您就可以使用expl3
。
\input expl3-generic
\ExplSyntaxOn
\cs_new:Npn \range #1 #2 #3
{% #1 is the step, #2 the starting point, #3 the upper bound
#2
\int_step_function:nnnN { #2 + #1 } { #1 } { #3 } \user_addtorange:n
}
\cs_new:Nn \user_addtorange:n { , #1 }
\ExplSyntaxOff
\range{2}{3}{10}
\edef\therange{\range{2}{3}{10}}
{\tt\meaning\therange}
\bye
该函数\int_step_function:nnnN
的语法如下
\int_step_function:nnnN { <start> } { <step> } { <end> } <function>
应该<function>
是一个单参数函数(宏,用普通的 TeX 术语来说),它将以显而易见的方式传递通过循环得到的所有整数。只<end>
传递不超过的整数。该函数将扩展为,<current integer>
。开头是预先添加的,因此我们不会遇到虚假逗号的问题。
没有的版本expl3
,只是为了好玩。
\def\range#1#2#3{% #1 = step, #2 = start, #3 = upper bound
\betterrange{#2}{#3}{#1}%
}
\def\betterrange#1#2#3{% #1 = start, #2 = upper bound, #3 = step
#1%
\ifnum\numexpr#1+#3>\numexpr#2\relax
\expandafter\gobble
\else
\expandafter\firstofone
\fi
{\expandafter,\expandafter\betterrange\expandafter{\the\numexpr#1+#3}{#2}{#3}}%
}
\def\gobble#1{}
\def\firstofone#1{#1}
\range{2}{3}{10}
\edef\therange{\range{2}{3}{10000}}
\show\therange
\bye
答案4
这是可扩展循环的典型问题。这里展示了各种解决方案。我展示了另一种使用\fornumstep
OpTeX 可扩展的解决方案(luaTeX + 增强型纯 TeX):
\def\range#1#2#3{\fornumstep #1: #2..#3 \do{##1,}}
%test:
\edef\therange{\range{2}{3}{10}}
\meaning\therange
\bye