我发布了这两个问题
现在我想合并这两个问题:
\documentclass{article}
\makeatletter
\newcounter{a@c}
\newcounter{b@c}
\newcounter{c@c}
\newcounter{dummycounter}
\newtoks\a@t
\newtoks\c@t
%\newcommand{\comma}{[[\thea@c,\theb@c]]\stepcounter{b@c}}
\newcommand{\Aa}[1]{%
\ifnum\thea@c>0\a@t=\expandafter{\the\a@t\@elt\relax #1}%
\else\a@t=\expandafter{#1}%
\fi%
\stepcounter{a@c}
}
\newcommand{\printauthor}{%
\setcounter{dummycounter}{0}%
\def\@elt##1{%
\ifnum\c@dummycounter < \numexpr\c@a@c - 2\relax%
,
\else
{ and }%
\fi
\stepcounter{dummycounter}%
}
}
\newcommand{\reset}{%
\setcounter{a@c}{0}
\a@t={}
%\newline
}
\newcommand{\Af}{%
\printauthor
\begingroup
\ifnum\thec@c>0
\edef\x{\endgroup\noexpand\c@t={\the\c@t, (\the\a@t)}}%
\else
\edef\x{\endgroup\noexpand\c@t={(\the\a@t)}}%
\fi
\x
\stepcounter{c@c}%
\reset%
%\newline
}
\newcommand{\Pp}{\the\c@t}
\makeatother
\begin{document}
\Aa{a}
\Aa{b}
\Aa{c}
\Af
\Aa{d}
\Af
\Aa{pippo}
\Aa{pluto}
\Af
\Aa{paperino}
\Af
\Pp
\end{document}
我得到的结果是
(a and b and c), (d), (pippo and pluto), (paperino)
但这是不必要的,因为我想获得
(a, b and c), (d), (pippo and pluto), (paperino)
我该如何解决这个问题?事实上,这看起来非常简单,用 Python 或 C 或任何其他语言都很容易。在我看来,在 TeX 中,即使是最简单的事情也需要大量的代码和技巧……你能帮助我吗?
答案1
您似乎想到的应用程序中的重要一点是不要强制过于严格的设置。
因此,我将每个作者的列表存储为其本身,但作为另一个命令的参数,可以在使用时以多种方式进行设置。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\addauthors}{m}
{
\mapo_addauthors:n { #1 }
}
\NewDocumentCommand{\printauthors}{+O{,~}}
{
\mapo_printauthors:n { #1 }
}
\seq_new:N \g_mapo_authors_seq
\seq_new:N \l__mapo_temp_seq
\cs_new_protected:Nn \mapo_addauthors:n
{
\seq_gput_right:Nn \g_mapo_authors_seq { \__mapo_wrapper:n { #1 } }
}
\cs_new_protected:Nn \mapo_printauthors:n
{
\cs_set_eq:NN \__mapo_wrapper:n \__mapo_standardprint:n
\seq_use:Nn \g_mapo_authors_seq { #1 }
}
\cs_new_protected:Nn \__mapo_standardprint:n
{
\seq_set_split:Nnn \l__mapo_temp_seq { \\ } { #1 }
\seq_use:Nnnn \l__mapo_temp_seq { ~and~ } { ,~ } { ~and~ }
}
\ExplSyntaxOff
\begin{document}
\addauthors{
a \\
b \\
c
}
\addauthors{d}
\addauthors{pippo \\ pluto}
\addauthors{paperino}
\printauthors
\medskip
\printauthors[\par\medskip]
\end{document}
如您所见,该代码并不比其他代码长很多,而且非常灵活。
答案2
如果我看到给定的“用户环境”(代码的最后十二行)和期望的输出,那么我可以说:在 TeX 原始级别上执行此操作非常简单:
\def\alist{}\def\plist{}
\def\Aa#1{\edef\alist{\alist,\detokenize{#1}}}
\def\Af{\edef\plist{\ifx\plist\empty\else\plist, \fi
(\ifx\alist\empty\else\expandafter\applyand\alist,,\fi)}%
\def\alist{}%
}
\def\Pp{\scantokens\expandafter{\plist}}
\def\applyand #1,#2,#3,{%
\ifx,#1,\else \ifx,#3, and \else, \fi\fi #2%
\ifx,#3,\else \fihere \applyand #2,#3,\fi
}
\def\fihere#1\fi{\fi#1}
\Aa{a}
\Aa{b}
\Aa{c}
\Af
\Aa{d}
\Af
\Aa{pippo}
\Aa{pluto}
\Af
\Aa{paperino}
\Af
\Pp
答案3
我现在从您的其他问题中看到,尽管您评论说在现代编程语言中做到这一点是多么容易,但您还是决心将这些语言与 TeX 进行比较,拒绝基于 TeX 构建的现代接口。因此,毫不奇怪,TeX 的情况似乎更加困难。为了进行公平的比较,您需要比较 TeX 创建时或至少最终确定时可用的其他语言。也许 80 年代早期可用的其他语言确实使这变得容易 - 我不知道。但将它与今天的 Python 和 C 进行比较就像比较苹果和橘子,这绝不公平!
这里使用现代界面实现,不需要任何技巧,代码行数也相对较少。诚然,宏的名称等比 TeX 使用的要长,但好处是代码更加透明和可读。
我也不推荐使用宏\Aa
作为终端用户界面。它们会让你的问题更难理解,也会让命令更难使用。即使你是唯一一个终端用户,情况也是如此。也许在这种情况下尤其如此,因为如果你像我一样,你不会写文档对于仅供私人使用的代码。
无论如何,我们可以使用更少的代码行,因为我们不需要重新发明完好的轮子。
这里,\addauthor{}
添加作者;\authorout
完成作者组;并\printout
打印出整个列表。由于我基本上不知道您要做什么,因此所提供的工具可能并不适合您的目的,但它们应该可以为您提供基本的想法。
定义了两个逗号分隔的列表。一个保存当前作者组。另一个保存作者组的整体列表。我们不需要计算任何内容,因为当我们使用逗号列表时,我们可以告诉 TeX 应该在 2 项列表中的项目之间、3+ 项列表中的最后 2 项以及 3+ 项列表中的剩余项目对之间使用哪些分隔符。我们还具有根据需要清除列表所需的功能。在这里,我假设排版后应该清除整个列表。
请注意,只需在调用宏时使用适当的签名来使用保存当前作者组的逗号列表即可激活完全扩展。
\clist_put_right:Nx \l_mapo_authors_clist { ( \clist_use:Nnnn \l_mapo_author_clist { ~and~ } { ,~ } { ~and~ } ) }
用于将已完成的作者组的内容添加到作者组主列表中。 表示:Nx
第二个参数应完全展开,以确保我们将列表的内容添加到主列表中,然后在下一行中清除它以准备下一个作者组。
相比之下
\clist_put_right:Nn \l_mapo_author_clist { #1 }
具有签名:Nn
,表明第二个参数不应被特殊处理,因为这里不需要。
因此,无需担心\expandafter
要使用多少个 s 或将它们放在哪里。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\clist_new:N \l_mapo_author_clist
\clist_new:N \l_mapo_authors_clist
\tl_new:N \l_mapo_end_tl
\tl_set:Nn \l_mapo_end_tl {}
\NewDocumentCommand \addauthor { m }{
\clist_put_right:Nn \l_mapo_author_clist { #1 }
}
\NewDocumentCommand \authorout {}{
\clist_put_right:Nx \l_mapo_authors_clist { ( \clist_use:Nnnn \l_mapo_author_clist { ~and~ } { ,~ } { ~and~ } ) }
\clist_clear:N \l_mapo_author_clist
}
\NewDocumentCommand \printout {}{
\clist_use:Nnnn \l_mapo_authors_clist { ~, } { ,~ } { ,~ }
\l_mapo_end_tl
\clist_clear:N \l_mapo_authors_clist
}
\ExplSyntaxOff
\begin{document}
\addauthor{a}
\addauthor{b}
\addauthor{c}
\authorout
\addauthor{d}
\authorout
\addauthor{pippo}
\addauthor{pluto}
\authorout
\addauthor{paperino}
\authorout
\printout
\end{document}
编辑
为了回答评论中的问题,目的是修改上述代码以产生以下输出:
为此,我将修改每个作者的添加,而不是将每个作者组添加到整个列表中。为此,我们可以在添加作者时简单地测试包含当前作者组的逗号列表是否为空。如果为空,则我们在列表的添加部分前面加上所需的标签。如果不是,那么我们只需像往常一样添加新添加的内容即可。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\clist_new:N \l_mapo_author_clist
\clist_new:N \l_mapo_authors_clist
\tl_new:N \l_mapo_end_tl
\tl_set:Nn \l_mapo_end_tl {}
\NewDocumentCommand \addauthor { m }{
\clist_if_empty:NTF \l_mapo_author_clist
{
\clist_put_right:Nn \l_mapo_author_clist { \textsc{Authors:~} \textit{#1} }
}
{
\clist_put_right:Nn \l_mapo_author_clist { \textit{#1} }
}
}
\NewDocumentCommand \authorout {}{
\clist_put_right:Nx \l_mapo_authors_clist { \clist_use:Nnnn \l_mapo_author_clist { ~and~ } { ,~ } { ~and~ } }
\clist_clear:N \l_mapo_author_clist
}
\NewDocumentCommand \printout {}{
\clist_use:Nnnn \l_mapo_authors_clist { ~, } { ,~ } { ,~ }
\l_mapo_end_tl
\clist_clear:N \l_mapo_authors_clist
}
\ExplSyntaxOff
\begin{document}
\addauthor{a}
\addauthor{b}
\addauthor{c}
\authorout
\addauthor{d}
\authorout
\addauthor{pippo}
\addauthor{pluto}
\authorout
\addauthor{paperino}
\authorout
\printout
\end{document}
Authors:
请注意,要获取作者姓名之间的空格,我们需要~
而不是,因为
每当 expl3 语法处于活动状态时,它都会被忽略。(这就是为什么我们不必像通常那样避免不想要的空格或注释行尾以避免虚假空格的原因。缺点是我们确实想要的所有空格都必须明确编码。在这种情况下
~
是易碎空间——并不是牢不可破的——从上面最终作者组的输出可以看出。
答案4
我需要在引用空间中有一些类似的东西。
对于实名制(这大概是最终状态)来说,biblatex
已经提供了大量的资源。
在这里,我使用带有排序的 authoryear 样式,并定义一个自定义 cite 命令,该命令打印每个引用的第一作者,在引用之间执行,
and and
,并将引用组括在内(...)
:
平均能量损失
\begin{filecontents*}[overwrite]{\jobname.bib}
@book{peri,author = {Pericles},}
@book{hero,author = {Herodotus},}
@book{thuc,author = {Thucydides},}
@book{euri,author = {Euripides},}
@book{aesc,author = {Aeschylus},}
@book{atti,author = {Atticus},}
@book{leon,author = {Leonidas},}
@book{herc,author = {Hercules},}
@book{prax,author = {Praxiteles},}
\end{filecontents*}
\documentclass{article}
\usepackage[style = authoryear,
sortcites=true,
sorting=nyt,
]{biblatex}
\addbibresource{\jobname.bib}
\DeclareCiteCommand{\parenauthorcite}[\mkbibparens]%
{\usebibmacro{prenote}}
{%
\printnames[][1-1]{author}%
\ifthenelse{\value{citecount}=\value{citetotal}}%
{}%
{%
\ifnumcomp{\value{citecount}}{<}{\value{citetotal}-1}%
{\addcomma\addspace}%
{\addspace and\addspace}%
}%
%
}%
{%
}%
{\usebibmacro{postnote}}%
\begin{document}
\parenauthorcite{hero,thuc}
\parenauthorcite{atti}
\parenauthorcite{euri,aesc,prax,leon}
\parenauthorcite{herc}
\end{document}