我正在尝试制作一个无包命令,该命令在逗号分隔的列表中应用命令,然后根据语法要求将单词“and”添加到输出中。我已经已经得到了一些帮助构建\apply
命令,现在我正在处理\addandtolist
命令。\apply
和\addandtolist
命令似乎可以单独工作,但不能组合使用。具体来说,在以下测试文档中,测试 3 失败,但如果从文档中删除测试 3,测试 1 和 2 会成功:
\documentclass[letterpaper]{article}
% This command is for applying a single command to a comma-separated list of tokens, and listing the results separated by ", "
\makeatletter
\newcommand{\apply}[3][, ]{
% #1: optional separator to print between applications; default=[, ]
% #2: command to apply;
% #3: list to apply command to
\def\itemsep{\def\itemsep{#1}} % first call to \itemsep prints nothing; later calls print #1
\def\zz{\itemsep#2}%
\@for \listelement:=#3\do{\expandafter\zz\expandafter{\listelement}}%
}
\makeatother
% The following command is for adding an "and" to a comma-separated list, if grammatically appropriate:
\newcommand{\addandtolist}[1]{%
\directlua{
s = string.explode("#1","")
commacounter=0
lastcomma=-1
for key, value in pairs(s) do
if value=="," then
commacounter=commacounter+1
lastcomma=key
end
end
if commacounter==1 then
s[lastcomma]=" and "
elseif commacounter>1 then
s[lastcomma]=", and "
end
t=""
for key, value in pairs(s) do
t=t..value
end
tex.sprint(t)
}
}
\begin{document}
\noindent Test 1 (succeeds): As hoped, these letters print in lowercase:\\
\apply{\lowercase}{U,V,W,X,Y}\\
\newcommand{\ComplicatedCommand}[1]{\lowercase{#1}}
\apply{\ComplicatedCommand}{U,V,W,X,Y}\\
\
\noindent Test 2 (succeeds): These lists get an ``and'' added to them if appropriate:\\
\addandtolist{u}\\
\addandtolist{u, v}\\
\addandtolist{u, v, w, x, y}\\
\noindent Test 3 (fails): Calling the ``addandtolist" command on the output of the apply command returns at error:\\
\addandtolist{\apply{\lowercase}{U,V,W,X,Y}}\\
\addandtolist{\apply{\ComplicatedCommand}{U,V,W,X,Y}}\\
\end{document}
排除检验 3 后的结果:
包含测试 3 时出错:
如果最终结果能与 Lua 配合使用,那就太棒了,但我也接受非 Lua 解决方案。\usepackage
不过,我确实希望结果不包含任何调用,因为我想避免调用可能最终干扰其他包的包。
非常感谢您提供的帮助!
答案1
由于您正在遍历 tex 中的列表,因此我将添加and
使用相同类型的习语。
\documentclass[letterpaper]{article}
% This command is for applying a single command to a comma-separated list of tokens, and listing the results separated by ", "
\makeatletter
\newcommand{\apply}[3][, ]{%
% #1: optional separator to print between applications; default=[, ]
% #2: command to apply;
% #3: list to apply command to
\def\zzitemsep{\def\zzitemsep{\ifnum\count@=\z@\space and \else#1\fi}} % first call to \zzitemsep prints nothing; later calls print #1
\count@\z@
\@for \listelement:=#3\do{\advance\count@\@ne}%
\def\zz{\zzitemsep#2}%
\@for \listelement:=#3\do{\advance\count@\m@ne\expandafter\zz\expandafter{\listelement}}%
}
\makeatother
\begin{document}
\noindent Test 1 (succeeds): As hoped, these letters print in lowercase:\\
\apply{\lowercase}{U}\\
\apply{\lowercase}{U,V}\\
\apply{\lowercase}{U,V,W,X,Y}\\
\newcommand{\ComplicatedCommand}[1]{\lowercase{#1}}
\apply{\ComplicatedCommand}{U,V,W,X,Y}\\
\end{document}
这里进行两次计数列表,以便您知道何时添加and
。请注意使用更完整的列表结构,例如,expl3
列表长度已经“已知”。