Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have a string separated with commas. On that I want to get each element and apply a command. I have the following, which works.

\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}

But I would like to have the following

\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}

But the \let\#1\TokenTwo is giving an error. How can I use #1 with \let

share|improve this question
    
Why? Is it because it seems cleaner as opposed to using an intermediate macro \Source? You could also process this list using etoolbox and not have to worry about re-assigning something to #1. –  Werner Aug 22 '12 at 2:56
    
@Werner I tried a quick demo with etoolbox, but it does not strip trailing spaces from each entry. Thus the output is slightly different from the one which seems to be required from the example given. –  Joseph Wright Aug 22 '12 at 6:47
add comment

2 Answers

up vote 7 down vote accepted

#1 gets replaced at the first call of the macro. If macro \cadd

\newcommand{\cadd}[1]{
    \whiledo{\not\equal{#1}{}}
    {
        \GetTokens{TokenOne}{TokenTwo}{#1}
        \textbf{\TokenOne}
        \let\#1\TokenTwo
    }
}

is called as \cadd{a,b,c}, then it becomes to:

<space>
\whiledo{\not\equal{a,b,c}{}}<space>
{<space>
  \GetTokens{TokenOne}{TokenTwo}{a,b,c}<space>
  \textbf{\TokenOne}<space>
  \let\#1\TokenTwo
}<space>
  • The line \let\#1\TokenTwo consists of the \let assignment \let\#=1 and \TokenTwo. #1 is only replaced in macro expansion with the first argument.
  • There are lots of space tokens (caused by the end of line):

    • The first is ignored in vertical mode, because the paragraph has not yet started.
    • The second is ignored, if \whiledo reads the loop body as undelimited argument.
    • The third and fourth will be present in the output.
    • The last is removed because of the end of paragraph.

    Space tokens at the line end can be avoided by using the comment char, as seen in the following example.

There are many parsers for comma separated lists. One of them is provided by package 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}

Result

share|improve this answer
    
It works like a charm. Thank you very much! Vote +1. –  cacamailg Aug 22 '12 at 13:42
add comment

Heiko has covered the detail here nicely. For completeness, a solution using the LaTeX3 comma-list mapping function \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}

The underlying idea is much the same as Heiko's answer: rather than have to do the mapping by hand, use a pre-built command that deals with finding the end of the list.

share|improve this answer
    
Also works very nicely. Thanks! Vote +1. –  cacamailg Aug 22 '12 at 13:45
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.