トークン化してコマンドを適用する

トークン化してコマンドを適用する

カンマで区切られた文字列があります。その上で各要素を取得してコマンドを適用したいと思います。次のコードが動作します。

\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ループ本体を区切られていない引数として読み取る場合、2 番目は無視されます。
    • 3 番目と 4 番目は出力に含まれます。
    • 最後は段落の終わりのため削除されます。

    次の例に示すように、コメント文字を使用すると、行末のスペース トークンを回避できます。

カンマ区切りリスト用のパーサーは多数あります。そのうちの 1 つはパッケージによって提供されます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 の回答とほぼ同じです。つまり、手動でマッピングを行うのではなく、リストの末尾を見つけるための事前に構築されたコマンドを使用します。

関連情報