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.

This question is clearly related to How can I store variables and iterate over them?.

I'm sorry to ask such a close one, but I really don't understand the answer in plain TeX by David Carlisle.

Basically, I'd like to make a template in LaTeX, compatible with plain LaTeX/pdfLaTeX (no lua code), with as few dependencies as possible, that would allow me to get personal information this way:

\adduser{John Doe}{UK}
\adduser{M. Dupont}{France}
\adduser{M. Martin}{Belgium}{France}
\adduser{Jan Jansen}{Netherlands}
\adduser{Matti Meikäläinen}{Netherlands}{Finland}

And output something like that:

John Doe(a), M.Dupont(b), M. Martin(b, c), Jan Jansen(d), Matti Meikäläinen(d, e)

a: UK

b: France

c: Belgium

d: Netherlands

e: Finland

I'm sure this is possible, but in plain LaTeX, this seems very difficult. Any idea?

share|improve this question
    
The problem is that I did not understand it. I'm reading some doc about TeX right now (namely TeX by topic), but I'm lost. I'm used to C, Python, Go, GNU Octave, a bit of Fortran, but TeX, I just can't get it. The template is due tomorrow that's why I'm in a hurry, otherwise, I'd just take the time to learn it properly (and that's what I'm planning to do, but for tomorrow, it seems I'm screwed). –  Gael Feb 12 '13 at 17:48
    
I tried it and it worked well... But when I try to change something, it just breaks... –  Gael Feb 12 '13 at 17:50
    
Actually, I just need to understand how the code provided by David stores the values and how he gets them back... I can split the code and identify where he does that... When I read \def\xdo##1{\advance\count0 by 1 Input \the\count0 \space is: '##1'. }, I know what it does (extract the variable from the stack and display it instead of the ##1 token) but I really don't understand how which is really frustrating. –  Gael Feb 12 '13 at 18:03
    
Would a full answer here therefore be a walkthrough of David's approach? If so, I guess we can get him to give one ;-) –  Joseph Wright Feb 12 '13 at 18:04
    
Yes, that would be great! –  Gael Feb 12 '13 at 18:06

2 Answers 2

up vote 10 down vote accepted

enter image description here

Although there are some similarities with the other question, there are enough differences in the specifics that the code looks rather different. I added some comments this time:-)

\documentclass{article}

% 8bit encoded letters
\usepackage[latin1]{inputenc}

% a counter for locations
\newcounter{places}
\renewcommand\theplaces{\alph{places}}

% use @ in code
\makeatletter
% initialise the lists
\def\usernames{}
\def\userplaces{}


% #1 is person #2 is comma separated list
% It is harder and against LaTeX syntax rules
% to do as suggested and to have a variable number of
% brace groups.
\def\adduser#1#2{%
% add a comma if not the first
\ifx\usernames\@empty\else\g@addto@macro\usernames{, }\fi
%
% add the name and the start of the list of letters
% \@gobble will eat a comma before the first
\g@addto@macro\usernames{#1 (\@gobble}
%
% loop through a comma separated list
\@for\@tmp:=#2\do{%
% If we haven't seen this country before
% increment the counter
% Add the counter and the place name to the userplaces list
\expandafter\ifx\csname place@\@tmp\endcsname\relax
  \stepcounter{places}%
  \protected@edef\userplaces{\userplaces\par\theplaces: \@tmp}%
  \expandafter\edef\csname place@\@tmp\endcsname{\theplaces}%
\fi
% now get the letter stored for this place and add it to the list
\edef\@tmpb{\noexpand\g@addto@macro\noexpand\usernames{,\csname place@\@tmp\endcsname}}%
\@tmpb}
% add the closing )
\g@addto@macro\usernames{)}%
}
\makeatother


\adduser{John Doe}{UK}
\adduser{M. Dupont}{France}
\adduser{M. Martin}{Belgium,France}
\adduser{Jan Jansen}{Netherlands}
\adduser{Matti Meikäläinen}{Netherlands,Finland}

\begin{document}

\usernames

\userplaces

\end{document}
share|improve this answer
    
I really need to learn TeX. Thank you David, you were really helpful. As an additional question, is there any specific reference about the TeX language that you would recommend ? –  Gael Feb 12 '13 at 20:19
    
    
Little typo: \makeatoother -> \makeatother. (I would change it myself but I don't have the necessary privilege to make single-character edits.) –  John Wickerson Apr 18 '13 at 9:40
1  
@JohnWickerson thanks (thus revealing I edited the code after posting, note to self: don't do that:-) –  David Carlisle Apr 18 '13 at 10:43

The following solution allows you to submit more than one user name when calling \adduser. It will also sort the user names and place indices.

\documentclass[12pt]{article}
\usepackage{catoptions}
\makeatletter
\newcounter{placecnt}
\def\printplaces{}
\def\printusers{\noindent\userlist\def\userlist{}}
\def\auxuserlist{}
\def\cptxappto#1#2{\protected@edef#1{#1#2}}
\def\cptalphasortcommalist#1#2{%
  \begingroup
  \def\sort@tempa{}%
  \cptdocommalist*#1{%
    \cptxappto\sort@tempa{{\unexpanded{##1}}}%
  }%
  \cptalphasort\sort@tempa#2%
  \def#1{}%
  \cptdosisolist*\sort@tempa{%
    \cptxappto#1{\ifx#1\@empty\else,\fi\unexpanded{##1}}%
  }%
  \postgroupdef#1\endgroup
}

\begingroup
\catcode`\~=13
% #1= comma separated list of persons.
% #2= comma separated list of affiliations/places.
\gdef\adduser#1#2{%
  \def\userlist{}%
  \let\sav@nobreakspace~%
  \let~\relax
  \cptdocommalist{#1}{%
    \ifcsname thisuserplaces@\detokenize{##1}\endcsname\else
      \csn@edef{thisuserplaces@\detokenize{##1}}{}%
      \cptxappto\auxuserlist{\ifx\auxuserlist\@empty\else,\fi##1}%
    \fi
    \cptdocommalist{#2}{%
      \ifcsname thisplaceid@\detokenize{####1}\endcsname\else
        \stepcounter{placecnt}%
        \cptxappto\printplaces{%
          \endgraf\noindent
          \textsuperscript{\alph{placecnt}}\unskip####1%
        }%
        \csn@edef{thisplaceid@\detokenize{####1}}{\alph{placecnt}}%
      \fi
      \edef\am@tempa{\@nameuse{thisplaceid@\detokenize{####1}}}%
      \edef\am@tempb{\@nameuse{thisuserplaces@\detokenize{##1}}}%
      \xifinsetTF{,\am@tempa,}{,\am@tempb,}{}{%
        \aftercsname\cptxappto{thisuserplaces@\detokenize{##1}}{%
          \ifx\am@tempb\@empty\else,\fi\am@tempa
        }%
      }%
    }%
  }%
  \cptalphasortcommalist\auxuserlist<%
  \cptdocommalist*\auxuserlist{%
    \edef\am@tempa{\@nameuse{thisuserplaces@\detokenize{##1}}}%
    \cptalphasortcommalist\am@tempa<%
    \cptxappto\userlist{%
      \ifx\userlist\@empty\else, \fi
      ##1\unskip\textsuperscript{\am@tempa}%
    }%
  }%
  \let~\sav@nobreakspace
  \undefcs\sav@nobreakspace
}
\endgroup
\makeatother

% Note repeated entry of M. Martin for the same and different locations:
\adduser{M.~Martin, John Doe}{UK, Germany}
\adduser{M.~Martin, D.D.D.~Damiaan}{Belgium}
\adduser{M.~Martin, N.~Johnson}{Belgium, France}
\adduser{M.~Dupont}{France}
\adduser{John Doe, Jan Jansen}{Netherlands, UK}
\adduser{Matti Meikäläinen, M.~Dupont}{Netherlands, Finland}
\adduser{Steve Binns}{UK}

\begin{document}
\printusers
\par\bigskip
\printplaces
\end{document}

Example output

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.