如何定义一个不定参数(可能超过9个)的宏:先读入所有参数,并分析,再根据分析结果采取不同策略处理各个参数
问题比较抽象,先看一个简单例子:
需要定义一个宏 \qq,其参数数量不定,可以是 1-无穷个(超过9),期望效果:
\qq{P1}{P2} -> (P1/2)(P2/2) \qq{P1}{P2}……{Pn} -> (P1/n)(P2/n)……(Pn/n)
实现:
% 用户接口:初始化\P,并调底层 \storeP 实现:加工并存储各个参数到 \P 中,直到最后一个参数,再输出 \P \def\qq{\def\P{\relax}\count6120=0\relax\storeP} \def\qq{\let\P=\relax \count6120=0\relax\storeP} % \storeP 的实现代码(失败的教训): 尝试方案 1 (失败) \def\storeP#1{\advance\count6120 by 1\let\oldP=\P \def\PP{\oldP (#1/\the\count6120)}\let\P=\PP\@ifnextchar\bgroup{\storeP}{\P}} 尝试方案 2 (失败) \def\storeP#1{\advance\count6120 by 1\def\newP{\P (#1/\the\count6120)}\let\P=\PP\@ifnextchar\bgroup{\storeP}{\P}} 瞎尝试方案 x-1 (失败) \def\storeP#1{\advance\count6120 by 1\let\oldP=\P \edef\P{\noexpand\oldP (#1/\the\count6120)} \@ifnextchar\bgroup{\storeP}{\P}} 瞎尝试失败方案 x \def\storeP#1{\advance\count6120 by 1\let\oldP=\P \def\P{\noexpand\oldP (#1/\the\count6120)} \@ifnextchar\bgroup{\storeP}{\P}} 盲目骚操作 x + 1 % \edef \xdef \expanderafter …… 初步成功! \def\storeP#1{\advance\count6120 by 1\apptocmd{\P}{(#1/\the\count6120)}{\relax}{\relax}\@ifnextchar\bgroup{\storeP}{\P}} \qq{P1}{P2}{P3}{P4} 【期望的结果为(P1/4)(P2/4)(P3/4)(P4/4)】
这个例子看起来没什么实用性,
那好,大家再看下这个抽象问题背后的实际场景:选择题的自动排版
场景分析:
选项数量不确定,可能有多个(甚至超过9个,你懂的),
需要先读入所有选项,进行分析:找出最长选项,并结合选项数量决定如何排版(一行排几个)
选项数 | 可选排版方案:每行可能排多少选项 | |||
1 | 1 | |||
2 | 1 | 2 | ||
3 | 1 | 3 | ||
4 | 1 | 2 | 4 | |
5 | 1 | 2 | 3 | |
6 | 1 | 2 | 3 | |
7 | 1 | 2 | 4 | |
8 | 1 | 2 | 3 | 4 |
9 | 1 | 2 | 3 | |
10 | 1 | 2 | 4 | |
11 | 1 | 2 | 3 | 4 |
12 | 1 | 2 | 3 | 4 |
…… |
麻烦之处:
① 参数不定,还可能是无穷
② 需要先分析并做决策,再倒回去排版。
遇到一个参数分析一个,并将参数存储到一个内部宏中
目前选项可以自动支持 2-9 个参数,但被一个 Python 工程师吐嘈说支持不了 10 个参数,暴力写做不到无穷多个,还搞得模板还很臭
参考:
如果只是想遍历所有的参数,不需要先来一遍分析,再下决策然后倒回去排版,还是挺好实现的。例如:分分钟可以写出求和宏:
\def\addnext#1{\advance\count6120 by #1\@ifnextchar\bgroup{\addnext}{\the\count6120}} \def\sumup{\count6120=0\addnext} 效果 \sumup{2}{3}{5}{5}{2}{3}{5}{5}{2}{3}{5}{5}{2}{3}{5}{5}{2}{3}{5}{5}{2}{3}{5}{5} ……