标记并应用命令

标记并应用命令

我有一个用逗号分隔的字符串。我想获取每个元素并应用命令。我有以下内容,可以正常工作。

\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 的回答非常相似:不必手动进行映射,而是使用预先构建的命令来查找列表的末尾。

相关内容