我正在使用 LaTeX 排版戏剧剧本。每个角色都有一个自制的命令\<charactername>x
,该命令接受一个参数并将该文本输出为该角色的语音。例如,\tomx{Hi, I'm Tom}
表示汤姆说“嗨,我是汤姆”。
在每个场景的开头,我都需要一个出现在这个场景中的角色列表。目前,我正在手动完成这项工作,但要跟踪哪些角色在该场景中说了些什么,这是一个容易出错的任务,尤其是在角色拥挤的情况下。经常会有人被遗忘,我需要再三检查是否将每个人都包括在角色列表中。
我想知道是否可以稍微调整一下我的自定义语音命令,以便每个场景都有一个变量来保存该场景中出现的角色列表,并且每次\<charactername>x
调用其中一个命令时,如果角色名称不在列表中,它们会将该角色的名称附加到该列表中。如何解决这个问题?MWE 可能看起来像这样:
\documentclass{scrartcl}
\newcommand{\tomx}[1]{
% Alter this command (maybe?) to append "Tom" to the list of
% characters of the scene this command is used in if "Tom" is not yet present.
\textsc{Tom:} #1
}
\begin{document}
\section{In the supermarket}
% Call command here that lists characters in this scene, in this case only tom.
\tomx{Hi, I'm Tom!}
\end{document}
无需快速或花哨。任何帮助都非常感谢,提前致谢!
答案1
这里的困难在于知道哪些人会在后面出现,但人物列表必须先完成。
我在这里使用这种\label
方法并检查是否给出了标签,否则不会列出该人。
用 定义了一个新的人\NewPerson{foo}
,它自动定义\foox
并添加代码来检查标签是否存在等。
现在,命令\DisplayPersons
循环遍历所有定义的人员并存储本地人员,再次循环遍历这个较小的人员列表并应用\displayindividualperson
可以根据个人喜好进行更改的人员。
宏\PostPersonlist
可以\personlistheader
配置为提供其他样式。
注意:与任何\label
基于方法一样,至少需要运行两次编译
\documentclass{scrartcl}
\usepackage{refcount}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \g_luke_listofpersons_seq
\seq_new:N \l_luke_listofpersons_seq
\NewDocumentCommand{\addperson}{m}{%
\seq_gput_right:Nn \g_luke_listofpersons_seq {#1}
\seq_gremove_duplicates:N \g_luke_listofpersons_seq
}
\NewDocumentCommand{\addpersonlocal}{m}{%
\seq_gput_right:Nn \l_luke_listofpersons_seq {#1}
}
\cs_new:Npn \IfPersonCalledAlreadyF #1#2 {%
\seq_if_in:NnF \l_luke_listofpersons_seq {#1} {#2}
}
\NewDocumentCommand{\DisplayPersons}{}{%
\seq_clear:N \l_luke_listofpersons_seq
\group_begin:
\seq_clear:N \l_tmpa_seq
\seq_map_inline:Nn \g_luke_listofpersons_seq {%
\IfRefUndefinedExpandable{##1\thesection}{}{
\seq_put_right:Nn \l_tmpa_seq {\displayindividualperson{##1}}
}
}
\seq_if_empty:NF \l_tmpa_seq {
\PrePersonList
\seq_use:Nn \l_tmpa_seq {,~}
\PostPersonList
}
\group_end:
}
\ExplSyntaxOff
\NewDocumentCommand{\PostPersonList}{}{%
\bigskip%
}
\NewDocumentCommand{\displayindividualperson}{m}{%
\textbf{#1}%
}
\NewDocumentCommand{\PrePersonList}{}{%
{\large \bfseries Persons in Section \thesection}
}
\makeatletter
\NewDocumentCommand{\NewPerson}{m}{%
% Add this person to the global list
\addperson{#1}%
% Now define the personal \...x command
\expandafter\NewDocumentCommand\csname #1x\endcsname{+m}{%
%Check if the person has been called in the local section already
\IfPersonCalledAlreadyF{#1}{%
\addpersonlocal{#1}
% Add the personal to the local list, i.e. per section
% Check whether the label has been defined already
\protected@edef\@currentlabel{\thesection.#1}\label{#1\thesection}
}%
\textsc{#1:} ##1%
}% End of the \...x command
}% End of \NewPerson
\makeatother
\NewPerson{tom}
\NewPerson{frodo}
\NewPerson{Gandalf}
\begin{document}
\section{In the supermarket}
\DisplayPersons
\tomx{Hi, I'm Tom!}
\frodox{Hi, I'm Frodo!}
\section{At TeX.SE}
\DisplayPersons
\frodox{Hi, I'm Frodo!}
\frodox{I am going to Mordor}
\Gandalfx{Cast the ring into the fire!}
\tomx{Waiting for Godot}
\end{document}
更新并突出显示
\documentclass{scrartcl}
\usepackage{xcolor}
\usepackage{refcount}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \g_luke_listofpersons_seq
\seq_new:N \l_luke_listofpersons_seq
\NewDocumentCommand{\addperson}{m}{%
\seq_gput_right:Nn \g_luke_listofpersons_seq {#1}
\seq_gremove_duplicates:N \g_luke_listofpersons_seq
}
\NewDocumentCommand{\addpersonlocal}{m}{%
\seq_gput_right:Nn \l_luke_listofpersons_seq {#1}
}
\cs_new:Npn \IfPersonCalledAlreadyF #1#2 {%
\seq_if_in:NnF \l_luke_listofpersons_seq {#1} {#2}
}
\NewDocumentCommand{\DisplayPersons}{}{%
\seq_clear:N \l_luke_listofpersons_seq
\group_begin:
\seq_clear:N \l_tmpa_seq
\seq_map_inline:Nn \g_luke_listofpersons_seq {%
\IfRefUndefinedExpandable{##1\thesection}{}{
\seq_put_right:Nn \l_tmpa_seq {\use:c{##1h}}
}
}
\seq_if_empty:NF \l_tmpa_seq {
\PrePersonList
\seq_use:Nn \l_tmpa_seq {,~}
\PostPersonList
}
\group_end:
}
\ExplSyntaxOff
\NewDocumentCommand{\PostPersonList}{}{%
\bigskip%
}
\NewDocumentCommand{\displayindividualperson}{m}{%
\textbf{#1}%
}
\NewDocumentCommand{\PrePersonList}{}{%
{\large \bfseries Persons in Section \thesection}
}
\makeatletter
\NewDocumentCommand{\NewPerson}{m+m}{%
% Add this person to the global list
\addperson{#1}%
% Now define the personal \...x command
\expandafter\NewDocumentCommand\csname #1x\endcsname{+m}{%
%Check if the person has been called in the local section already
\IfPersonCalledAlreadyF{#1}{%
\addpersonlocal{#1}
% Add the personal to the local list, i.e. per section
% Check whether the label has been defined already
\protected@edef\@currentlabel{\thesection.#1}\label{#1\thesection}
}%
\textsc{#1:} ##1%
}% End of the \...x command
\expandafter\NewDocumentCommand\csname #1h\endcsname{}{%
#2{#1}%
}
}% End of \NewPerson
\makeatother
\NewPerson{tom}{\colorbox{green}}
\NewPerson{frodo}{\colorbox{yellow}}
\NewPerson{Gandalf}{\fcolorbox{yellow}{yellow!60!blue}}
\begin{document}
\section{In the supermarket}
\DisplayPersons
\tomx{Hi, I'm Tom!}
\frodox{Hi, I'm Frodo!}
\section{At TeX.SE}
\DisplayPersons
\frodox{Hi, I'm Frodo!}
\frodox{I am going to Mordor}
\Gandalfx{Cast the ring into the fire!}
\tomx{Waiting for Godot}
\end{document}