我有一个用逗号分隔的字符串。我想获取每个元素并应用命令。我有以下内容,可以正常工作。
\documentclass[12pt]{article}
\usepackage[trim]{tokenizer}
\newcommand{\cadd}[1]{
\def\Source{#1}
\whiledo{\not\equal{\Source}{}}
{
\GetTokens{TokenOne}{TokenTwo}{\Source}
\textbf{\TokenOne}
\let\Source\TokenTwo
}
}
\begin{document}
\cadd{a,b,c}
\end{document}
但我希望得到以下内容
\documentclass[12pt]{article}
\usepackage[trim]{tokenizer}
\newcommand{\cadd}[1]{
\whiledo{\not\equal{#1}{}}
{
\GetTokens{TokenOne}{TokenTwo}{#1}
\textbf{\TokenOne}
\let\#1\TokenTwo
}
}
\begin{document}
\cadd{a,b,c}
\end{document}
但\let\#1\TokenTwo
出现错误。我该如何#1
使用\let
答案1
#1
在第一次调用宏时被替换。如果宏\cadd
\newcommand{\cadd}[1]{
\whiledo{\not\equal{#1}{}}
{
\GetTokens{TokenOne}{TokenTwo}{#1}
\textbf{\TokenOne}
\let\#1\TokenTwo
}
}
被称为\cadd{a,b,c}
,那么它就变成:
<space>
\whiledo{\not\equal{a,b,c}{}}<space>
{<space>
\GetTokens{TokenOne}{TokenTwo}{a,b,c}<space>
\textbf{\TokenOne}<space>
\let\#1\TokenTwo
}<space>
- 该行
\let\#1\TokenTwo
由\let
赋值组成\let\#=1
,并且\TokenTwo
.#1
仅在宏扩展中被第一个参数替换。 有大量空格标记(由行尾引起):
- 在垂直模式下,第一个会被忽略,因为段落还没有开始。
\whiledo
如果将循环体读取为未限定的参数,则第二个将被忽略。- 第三和第四个将出现在输出中。
- 由于段落已结束,因此删除最后一个。
可以使用注释字符来避免行尾的空格标记,如以下示例所示。
有许多用于逗号分隔列表的解析器。其中一个由包提供kvsetkeys
:
\documentclass[12pt]{article}
\usepackage{kvsetkeys}
\makeatletter
\newcommand{\cadd}[1]{%
\comma@parse{#1}{\caddentry}%
}
\newcommand*{\caddentry}[1]{%
\textbf{[#1]}%
}
\makeatother
\begin{document}
\cadd{a,b,c}
\cadd{ a , b , c }
\cadd{abc, def, ghi}
\cadd{{ with spaces }, {a b c}}
\end{document}
答案2
Heiko 已经很好地介绍了细节。为了完整起见,使用 LaTeX3 逗号列表映射函数的解决方案\clist_map_inline:nn
\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand { \cadd } { m }
{ \clist_map_inline:nn {#1} { [ \textbf {##1} ] } }
\ExplSyntaxOff
\begin{document}
\cadd{a,b,c}
\cadd{ a , b , c }
\cadd{abc, def, ghi}
\cadd{{ with spaces }, {a b c}}
\end{document}
其基本思想与 Heiko 的回答非常相似:不必手动进行映射,而是使用预先构建的命令来查找列表的末尾。