在我们大学,我们学生用 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}
其结果是...