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 am trying to build a command similar to the \author command. It takes one argument with is actually a list of arguments separated by \and. The command needs to apply another command like \underline or \emph to each element of the list. My current approach is

\documentclass{minimal}
\newcommand{\mylist}[1]{%
    \def\and{\noexpand\endgroup \noexpand\underline\noexpand\begingroup}%
    \edef\myinternallist{\noexpand\underline\noexpand\begingroup #1\noexpand\endgroup}%
    \show\myinternallist%
    \myinternallist%
}
\begin{document}
    \mylist{Element1 \and Element2}
\end{document}

and \show\myinternallist yields

> \myinternallist=macro:
->\underline \begingroup Element1 \endgroup \underline \begingroup Element2\endgroup .

which looks ok to my untrained eye. However, the above code does'nt compile and I have no clue why it does'nt. The expected result looks like this: enter image description here

share|improve this question
    
First of all, \underline\begingroup abc\endgroup is illegal: you can't use \begingroup and \endgroup for delimiting the argument to a macro. –  egreg Apr 25 at 10:11
    
What do I have to use instead? As I said above, I am not that experienced. –  porst17 Apr 25 at 10:13
    
There are various tools in etoolbox or expl3. –  egreg Apr 25 at 10:14

2 Answers 2

up vote 7 down vote accepted

You indeed get

\underline \begingroup Element1 \endgroup \underline \begingroup Element2\endgroup

but unfortunately \underline\begingroup Element1 \endgroup is illegal, because \begingroup and \endgroup can't be used for delimiting a macro argument.

There are various tools for this; I'll show a solution based on expl3, the programming layer of the future LaTeX3.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\mylist}{ O{\underline} m }
 {
  % transfer control to an internal function
  \porst_mylist:nn { #1 } { #2 }
 }

\seq_new:N \l__porst_list_items_seq
\seq_new:N \l__porst_list_output_seq

\cs_new_protected:Npn \porst_mylist:nn #1 #2
 {
  % clear the output sequence
  \seq_clear:N \l__porst_list_output_seq
  % split the input at \and
  \seq_set_split:Nnn \l__porst_list_items_seq { \and } { #2 }
  % append each item to the output sequence
  \seq_map_inline:Nn \l__porst_list_items_seq
   {
    % #1 is the given argument, ##1 represents the current item
    \seq_put_right:Nn \l__porst_list_output_seq { #1 { ##1 } }
   }
  % output the sequence with something between items
  \seq_use:Nn \l__porst_list_output_seq {,~} % adjust
 }
\ExplSyntaxOff

\begin{document}

\mylist{Element1 \and Element2}

\mylist[\emph]{Element1 \and Element2}

\end{document}

The first step is splitting the input at the \and tokens; trailing and leading spaces will be removed; the second step is storing the “formatted” items in another sequence, for using this one with some separator between the items.

enter image description here

Another possible tool is etoolbox; but, as you see, it's much more complicated.

\documentclass{article}
\usepackage{etoolbox}

\makeatletter
\DeclareListParser*{\andlist@do}{\and}
\newcommand{\andlist@sep}{, }
\newcommand{\mylist}[2][\underline]{%
  \def\andlist@output{\@gobble}%
  \andlist@do{\andlist@handler{#1}}{#2}%
  \andlist@output
}
\appto\nocorrlist{\andlist@sep}

\newcommand{\andlist@handler}[2]{%
  \appto\andlist@output{\andlist@sep#1{#2\unskip}}%
}
\makeatother

\begin{document}

\mylist{Element1 \and Element2}

\mylist[\emph]{Element1\and Element2}

\end{document}
share|improve this answer
    
Would you mind providing a solution with etoolbox as well? I already use the etoolbox package and I would like to avoid loading an additional package like xparse. –  porst17 Apr 25 at 10:31
    
@porst17 I added it. –  egreg Apr 25 at 10:59
    
You are right. The expl3 version is much easier to understand. Thanks a lot! –  porst17 Apr 25 at 12:24
    
@porst17 With etoolbox it's more difficult to remove unwanted spaces and also to insert something only between items. –  egreg Apr 25 at 12:27

If you want a solution not requiring a package, use braces {}, but you'll need balance them in the definition. To hidden them when expanded just use \iffalse .. \fi:

\def\and{\unskip\iffalse{\fi} \noexpand\underline{\iffalse}\fi}%
\protected@edef\myinternallist{\noexpand\underline{#1}}%

\edefcannot be used with arbitrary stuff, so I use \protected@def, which means you must enclose the whole definition with \makatletter .. \makeatother. I've also added \unskip (to remove the space at the end of each block) and a space.

share|improve this answer

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.