我有一个宏,可以生成随机数列表并将其转换为字母进行打印。我想创建另一个宏来打印这些列表及其中间的文本。也就是说,如果
\first
生成 A、C、B、D,
则
\first{2}
返回 C
,我想要的功能如下:
sometext 包含 A、sometext 包含 C、sometext 包含 B、sometext 包含 D
sometext 包含的字母可能位于中间,并且可能因上下文而异。我使用 X 作为占位符,并使用 StrSubstitute 放置适当的字母。这不起作用,但我怀疑这更多地与以下事实有关:其中一个参数来自foreach
使用pgffor
我当前的工作代码(我想要注释掉的部分,因为它不起作用):
\documentclass[12pt,letterpaper]{article}
\def\colors{4}
\def\version{2}
\usepackage{xstring}
\usepackage{pgf}
\usepackage{pgffor}
\usepackage{etoolbox}
\usepackage{listofitems}
\usepackage{transparent}
\usepackage[first = 1, last = \colors, seed = \version]{lcg}
\setcounter{enumi}{1}
\newcommand{\row}{\item[Round \theenumi:] \stepcounter{enumi}}
\newcommand{\rn}{\rand\Alph{rand}}
\newcommand{\nums}[3]{\chgrand[counter = rand, seed = #2]
\foreach \i in {1,...,#1}{\ifnum\numexpr #3=0\rn~\else\ifnum\i=\numexpr #3\rn\else\makebox[0pt]{{\transparent{0}\rn}}\fi\fi}
}
\newcommand{\first}[1]{\nums{5}{\version}{#1}}
\newcommand{\expand}[3]{
\foreach \i in {1,...,#2}{
\StrSubstitute{#1}{X}{\i} %Code that works, but doesn't do what I want
% \StrSubstitute{#1}{X}{\expandafter{\csname #3\endcsname{\i}}} %Code that I want, but doesn't work
}
}
\newcommand{\dcinc}[2]{#1 text [#2] more text}
\begin{document}
\begin{description}
\row \expand{\dcinc{3}{M,2 X},}{5}{first}
\end{description}
\end{document}```
答案1
一方面:
该命令\nums
在内部用于\chgrand
执行分配。\nums
也这样做\pgffor
,这反过来也不是完全可扩展的。依次执行分配和其他不可扩展的命令意味着该命令\nums
不能仅通过扩展来发挥作用。
另一方面:
该命令在-loop\nums
的主体内使用,而使用-loops 时,主体通过扩展而不考虑 LaTeX 的-expansion-protection,这反过来意味着主体要么通过扩展来实现,要么通过 TeX 引擎的扩展保护来实现。\expand
\foreach
\foreach
\edef
\protect
\foreach
\protected\def
我建议定义并使用一个扩展保护的命令,\expansionprotectednums
它调用\nums
:
\documentclass[12pt,letterpaper]{article}
\def\colors{4}
\def\version{2}
\usepackage{xstring}
\usepackage{pgf}
\usepackage{pgffor}
\usepackage{etoolbox}
\usepackage{listofitems}
\usepackage{transparent}
\usepackage[first = 1, last = \colors, seed = \version]{lcg}
\setcounter{enumi}{1}
\newcommand{\row}{\item[Round \theenumi:] \stepcounter{enumi}}
\newcommand{\rn}{\rand\Alph{rand}}
\newcommand{\nums}[3]{%
\chgrand[counter = rand, seed = #2]%%%
\foreach \i in {1,...,#1}{%
\ifnum\numexpr(#3)\relax=0 %
\rn~%
\else
\ifnum\i=\numexpr(#3)\relax
\rn
\else
\makebox[0pt]{{\transparent{0}\rn}}%
\fi
\fi
}%%%
}
\makeatletter
\@ifdefinable\expansionprotectednums{%
\protected\def\expansionprotectednums{\nums}%
}%
\makeatother
\newcommand{\first}[1]{\expansionprotectednums{5}{\version}{#1}}
\newcommand{\expand}[3]{%%%
\foreach \i in {1,...,#2}{%%%
% \StrSubstitute{#1}{X}{\i} %Code that works, but doesn't do what I want
\StrSubstitute{#1}{X}{\csname #3\endcsname{\i}} %Code that I want, and seems to work
}%%%
}
\newcommand{\dcinc}[2]{#1 text [#2] more text}
\begin{document}
\begin{description}
\row \expand{\dcinc{3}{M,2 X},}{5}{first}
\end{description}
\end{document}
答案2
弄清楚问题中代码的意图相当困难,但我怀疑您不需要任何所使用的包。
\documentclass{article}
\ExplSyntaxOn
\seq_new:N\l_cb_seq
% start with a list of letters
\seq_set_from_clist:Nn \l_cb_seq {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}
\let\reseed\sys_gset_rand_seed:n
\def\shuffle{\seq_shuffle:N \l_cb_seq}
\def\nth{\seq_item:Nn \l_cb_seq}
\ExplSyntaxOff
\begin{document}
\reseed{1234}
\shuffle
2nd=\nth{2}, 5th=\nth{5}
\shuffle
2nd=\nth{2}, 5th=\nth{5}
\end{document}
这会用字母列表初始化一个序列,然后使用可重复的随机打乱对字母进行打乱,每次运行时都会给出相同的顺序,因为种子是明确设置的。然后显示两个示例项目,重新打乱列表并选择相同的项目编号,显示它们的新值。
在评论中澄清后
此版本构建了一个长度为 10 的随机列表,包含“A”、“B”、“C”、“D”,目前只有一个列表a
在此调用。它提供了对该列表第 n 个项目的访问函数,\nth{a}{4}
并提供了一个迭代器,该迭代器将使用 dupplied 函数中的指定字母循环遍历整个列表。
它产生终端输出
list a is: D,C,B,A,D,C,A,A,D,B
item 2 of list a: C
和排版
\documentclass{article}
\ExplSyntaxOn
% generate one random value from ABCD (1 is the position in the list, not used)
\cs_new:Npn \cb_rand_color:n #1 {\char_generate:nn{`A+\int_rand:nn{0}{3}}{11},}
% set up list "a" as a list of length 10
\clist_new:N\l_cb_lista_clist
\clist_set:Ne \l_cb_lista_clist {
\int_step_function:nnN {1} {10} \cb_rand_color:n
}
% seed for the random numbers
\let\reseed\sys_gset_rand_seed:n
%The #2 item from list #1
\def\nth#1#2{\clist_item:cn{l_cb_list#1_clist}{#2}}
% iterate pver the list
\def\printlist#1#2{\clist_map_inline:cn {l_cb_list#1_clist} {#2}}
\ExplSyntaxOff
\typeout{list a is: \UseName{l_cb_lista_clist}}
\typeout{item 2 of list a: \nth{a}{2}}
\begin{document}
\reseed{54321}% arbitrary fixed seed for repeateable results
\printlist{a}{text [M,2,#1] more text}
\end{document}