# Read authors from file

At our university, we students write a lot of summaries in LaTeX. We have the convention of adding a CONTRIBUTORS.txt file to the repository containing the document code, which lists all contributors line by line.

A file could look like this:

John Doe (jdoe)
Jane Roe (jroe)


I'd like to use those names in the \authors declaration.

The lines in the textfile (delimited by newlines) should be shown in the document separated with commas or newlines.

The current code I'm using:

\author{\InputIfFileExists{CONTRIBUTORS.txt}{\relax}{https://github.com/HSR-Stud/}}


...ignores newline characters, as LaTeX requires either \\ or an empty line to insert an actual newline in the generated document.

How can I insert all the names from the CONTRIBUTORS.txt file as comma or newline separated values?

Bonus question: How can I cut off the part inside the braces, so that the example file above would result in John Doe, Jane Roe?

Edit: The solution should also work if a person has two or more names (like "Gian Marco De Luca").

-
This would be very easy if your work flow allows you to process CONTRIBUTORS.txt with a script (in python or awk or ...) before inclusion in your LaTeX document. Since a makefile answers another of your questions here that's likely. Others on this site may provide a TeX only solution. – Ethan Bolker Jan 13 at 2:17
@EthanBolker Thanks, that's a very good point that I totally forgot about :) Still, if there is a native TeX solution that would be nice. – Danilo Bargen Jan 13 at 2:48

## 3 Answers

Here's a version with LaTeX3 macros:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\authorsfromfile} { O{,~} m }
{
\IfFileExists{#2}
{ \bargen_authors:nn { #1 } { #2 } }
{ \author{\texttt{https://github.com/HSR-Stud/}} }
}
\ior_new:N \l_bargen_file_ior
\seq_new:N \bargen_authors_seq
\cs_new_protected:Npn \bargen_authors:nn #1 #2
{
\seq_clear:N \l_bargen_authors_seq
\ior_open:Nn \l_bargen_file_ior { #2 }
\ior_map_inline:Nn \l_bargen_file_ior
{
\seq_put_right:Nx \l_bargen_authors_seq { \tl_trim_spaces:n { ##1 } }
}
\author { \seq_use:Nnnn \l_bargen_authors_seq { #1 } { #1 } { #1 } }
}
\ExplSyntaxOff

\begin{document}

\authorsfromfile{CONTRIBUTORS.txt}
\title{Document}
\maketitle

\end{document}


You can also do

\authorsfromfile[\and]{CONTRIBUTORS.txt}


that would use the traditional \and separator between authors.

Basically we read the file line by line and deliver the sequence thus obtained to the \author macro, with items separated by the optional argument to \authorsfromfile (default is "comma and space").

The advantage of this approach is that the line

\seq_put_right:Nx \l_bargen_authors_seq { \tl_trim_spaces:n { ##1 } }


can be modified in various ways, for example to process the input line for changing the appearance of the nickname.

A "classical" implementation, where we use the catchfile package to read the file; each line is delimited by ^^J, a character that won't appear in any reasonable text file. Also the nickname will be stripped off; the names are inserted in a \mbox in order not to split them across lines in the title page.

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{catchfile}

\makeatletter
\newcommand{\authorsfromfile}[2][, ]{%
\IfFileExists{#2}
{\CatchFileDef\authors@list{#2}{\endlinechar=^^J }\authors@do{#1}}
{\author{\texttt{https://github.com/HSR-Stud/}}}%
}
\def\authors@final@list{}
\def\authors@do#1{%
\def\authors@sep{#1}%
\expandafter\authors@do@aux\authors@list\@nil
}
\def\authors@do@aux#1^^J#2\@nil{%
\authors@strip@parens{#1}%
\expandafter\g@addto@macro\expandafter\authors@final@list\expandafter{\authors@current}%
\if\relax\detokenize{#2}\relax
\author{\authors@final@list}%
\expandafter\@gobble
\else
\expandafter\g@addto@macro\expandafter\authors@final@list\expandafter{\authors@sep}%
\expandafter\@firstofone
\fi
{\authors@do@aux#2\@nil}%
}
\def\authors@strip@parens#1{\authors@strip@aux#1 (\@nil}
\def\authors@strip@aux#1 (#2\@nil{\def\authors@current{\mbox{#1}}}
\makeatother

\begin{document}

\authorsfromfile{CONTRIBUTORS.txt}
\title{Document}
\maketitle

\end{document}


Again, one can also call this as

\authorsfromfile[\and]{CONTRIBUTORS.txt}


to get the standard separation between different authors. If the file is missing, a standard "author" will appear.

As it is it won't work if the file exists but is empty; one might add a check for it.

In order to make a long list of authors be well typeset by the article class you need to change \maketitle or, more precisely, \@maketitle:

\makeatletter
\def\@maketitle{%
\newpage
\null
\vskip 2em%
\begin{center}%
\let \footnote \thanks
{\LARGE \@title \par}%
\vskip 1.5em%
\begin{minipage}{.6\textwidth}
\large\centering\@author
\end{minipage}
\vskip 1em%
{\large \@date}%
\end{center}%
\par
\vskip 1.5em}
\makeatother


Here's what's printed if the file contains

John Doe (jdoe)
Jane Roe (jroe)
Christian Fässler
Jonas Furrer
Danilo Bargen


-
 This looks nice, but the requirement of LaTeX3 is a disadvantage, as many people still use Texlive2009 (which afaik doesn't ship LaTeX packages). – Danilo Bargen Jan 13 at 14:52 @DaniloBargen Happily also Debian based distributions have TeX Live 2012, now. – egreg Jan 13 at 15:51 @DaniloBargen I've added a "classical" implementation – egreg Jan 13 at 21:41 Thanks for your effort, I'll accept your answer :) Two details I noted: It doesn't cut off the part inside the parentheses (but that wasn't strictly required) and if the author list is too long, it gets cut off. I worked around that by using \\ as a separator, but a generic approach that would work with commas too would be nicer. Also, I think it would probably be cleaner to simply "return" the text to be used inside \author, so that the user could still process it, don't you think? – Danilo Bargen Jan 13 at 22:06 @DaniloBargen You should redefine \maketitle for that. I'll add both the nickname stripping and a suggestion on how to modify \maketitle for the article class. – egreg Jan 13 at 22:19
show 3 more comments

One way would be to use the datatool package:

## Notes:

• The usual separators is a comma, but we can redefine that to be a space using \DTLsetseparator{ }.
• \DTLiffirstrow is used to ensure that we don't add a comma separators in the output until after the first row has been printed.
• To handle the case of middle names we make use of \DTLifnull to test if the 3 or 4 fields were provided.

## Code:

\documentclass{article}
\usepackage{datatool}

\usepackage{filecontents}% Comment to prevent overwriting CONTRIBUTORS.txt
\begin{filecontents*}{CONTRIBUTORS.txt}
John Doe (jdoe)
Jane Roe (jroe)
John Michael Doe (jmdoe)
\end{filecontents*}

\begin{document}

\DTLsetseparator{ }
\DTLloadrawdb[
noheader,
keys={
FirstName,%
MiddleOrLastName,%
LastNameOrUserId,%
UserIdWithMiddleName%
}]{MyDB}{CONTRIBUTORS.txt}

\textbf{Contributors:}
%\DTLdisplaydb{MyDB}\par% useful for debugging
\DTLforeach{MyDB}{
\FirsName=FirstName,%
\MiddleOrLastName=MiddleOrLastName,%
\LastNameOrUserId=LastNameOrUserId,%
\UserIdWithMiddleName=UserIdWithMiddleName%
}{%
\DTLiffirstrow{ }{, }% add comma separator AFTER first entry
\DTLifnull{\UserIdWithMiddleName}{%
\FirsName{} \MiddleOrLastName
}{%
\FirsName{} \MiddleOrLastName{} \LastNameOrUserId
}%
}.

\end{document}

-
 Thanks for the answer, this looks interesting. I guess this wouldn't work if the contributors have middle names (like John Michael Doe (jmdoe), right? Would there be a fix for that? (Sorry for not clarifying that from the beginning...) – Danilo Bargen Jan 13 at 12:09 @DaniloBargen: Have updated solution to allow for optional middle names. – Peter Grill Jan 13 at 21:20

For reference, here would be a Makefile/awk/sed solution as proposed by @ethan-bolker:

contributors.tex:
echo "% Autogenerated, do not edit" > contributors.tex
echo "\\newcommand{\\contributors}{awk '{split($$0, a, \"(\"); gsub(/[ \t]+$$/, \"\", a[1]); printf(\"%s, \", a[1])}' CONTRIBUTORS.txt | sed 's/, //'}" >> contributors.tex


It can be used by including contributors.tex:

\input{contributors.tex}
\author{\contributors}
`

Which results in...

-