从文件读取作者

从文件读取作者

在我们大学,我们学生用 LaTeX 写了很多总结。我们习惯在包含文档代码的存储库中添加一个 CONTRIBUTORS.txt 文件,该文件逐行列出所有贡献者。

文件可能看起来像这样:

John Doe (jdoe)
Jane Roe (jroe)

我想在\authors声明中使用这些名称。

文本文件中的行(以换行符分隔)应在文档中以逗号或换行符分隔显示。

我当前正在使用的代码:

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

...忽略换行符,因为 LaTeX 需要\\或空行来在生成的文档中插入实际的换行符。

我如何将 CONTRIBUTORS.txt 文件中的所有名称以逗号或换行符分隔的值插入?

附加问题:我怎样才能截断括号内的部分,以便上面的示例文件能够产生结果John Doe, Jane Roe


编辑:如果一个人有两个或多个名字(例如“Gian Marco De Luca”),该解决方案也应该有效。

答案1

以下是带有 LaTeX3 宏的版本:

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

您还可以

\authorsfromfile[\and]{CONTRIBUTORS.txt}

将使用\and作者之间的传统分隔符。

基本上,我们逐行读取文件并将获得的序列传递给\author宏,其中项目由可选参数分隔\authorsfromfile(默认为“逗号和空格”)。

这种方法的优点是

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

可以通过多种方式进行修改,例如处理输入行以改变昵称的外观。


一种“经典”的实现,我们使用包catchfile来读取文件;每行由 分隔^^J,该字符不会出现在任何合理的文本文件中。昵称也将被删除;名称插入到 中,\mbox以免在标题页中将它们拆分成多行。

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

同样,也可以将其称为

\authorsfromfile[\and]{CONTRIBUTORS.txt}

获得不同作者之间的标准区分。如果文件缺失,则会出现标准“作者”。

如果文件存在但是为空,它将不起作用;可以添加检查。

为了使一长串的作者能够按照类别进行良好的排版,article您需要进行以下更改\maketitle,或者更准确地说\@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

如果文件包含以下内容,则会打印以下内容

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

在此处输入图片描述

答案2

一种方法是使用包裹datatool

在此处输入图片描述

笔记:

  • 通常的分隔符是逗号,但我们可以使用 将其重新定义为空格\DTLsetseparator{ }
  • \DTLiffirstrow用于确保在打印第一行之前我们不在输出中添加逗号分隔符。
  • 为了处理中间名的情况,我们利用\DTLifnull测试是否提供了 3 或 4 个字段。

代码:

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

答案3

作为参考,这里是@ethan-bolker 提出的 Makefile/awk/sed 解决方案:

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

可以通过以下方式使用contributors.tex

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

其结果是...

截屏

相关内容