![expl3-strategy 根据文档内容自动更新文档标题](https://linux22.com/image/395491/expl3-strategy%20%E6%A0%B9%E6%8D%AE%E6%96%87%E6%A1%A3%E5%86%85%E5%AE%B9%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0%E6%96%87%E6%A1%A3%E6%A0%87%E9%A2%98.png)
语境
当前的问题出现了:
- 尝试改进我在问题中解释的目标(Expl3' tl 变量存储 \seq_map_inline 的结果:在文章标题中可以,但在 beamer 的标题中不行),
- 为了解释为什么使用
\exp_not:N
而不是\exp_not:V
,正如 egreg 在回答我的另一个问题时所建议的那样(\TeX 和 \LaTeX 以不同的方式 expl3-x-written(穷举扩展)到辅助文件),在我的用例中毫无用处。
目的(总结)
我有一个主 ( beamer
) 文档,例如main.tex
,其内容根据目标受众而变化。为此,main.tex
输入一个或多个子文件,例如 5 个子文件:topic1.tex
、topic2.tex
、topic3.tex
、topic4.tex
、
topic5.tex
。
每个主题(文件)都有一个主题标题,我希望主文档的标题自动成为输入的主题标题列表(并且仅是输入的主题)。
为此,我采用了以下策略:
- 在每个主题文件的开头,通过
\topictitle
宏指定主题标题。 - 每次使用时,该宏都会将相应的主题标题附加到
\g_topics_seq
序列的右侧。 - 在(主)文档的末尾:
- 序列的内容
\g_topics_seq
放在\g_presentation_title_tl
标记列表中, - (未展开
\exp_not:V
:) 的内容\g_presentation_title_tl
被x
写入辅助.sbj
文件。
- 序列的内容
- 在(主要)文档序言的末尾(因此在下一个编译中):
- 设置临时标记列表
x
以包含辅助文件的内容, - 此临时令牌列表的内容被传递给
\title
。
- 设置临时标记列表
以下 MCE 是该策略的实现,但我想知道是否expl3
可以提供更好的策略。
\documentclass{beamer}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{filecontents}
\usepackage[check-declarations]{expl3}
\usepackage{xparse}
\begin{filecontents*}{topic1}
\topictitle{% \TeX{},
\LaTeX{} and café%
}
\begin{frame}
\TeX{}, \LaTeX{} and café are nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic2}
\topictitle{Topic 2}
\begin{frame}
Topic 2 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic3}
\topictitle{Topic 3}
\begin{frame}
Topic 3 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic4}
\topictitle{Topic 4}
\begin{frame}
Topic 4 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic5}
\topictitle{Topic 5}
\begin{frame}
Topic 5 is nice!
\end{frame}
\end{filecontents*}
\ExplSyntaxOn
\seq_new:N \g_topics_seq
\tl_new:N \g_presentation_title_tl
\iow_new:N \g_output_stream
\NewDocumentCommand{\topictitle}{m}
{
\__topic_title:n {#1}
}
\cs_new_protected:Npn \__topic_title:n #1
{
\seq_gput_right:Nn \g_topics_seq {#1}
}
\AtEndDocument
{
\tl_gset:Nx \g_presentation_title_tl
{
\seq_use:Nn\g_topics_seq {,~}
}
\iow_open:Nn \g_output_stream { \c_sys_jobname_str.sbj }
\iow_now:Nx \g_output_stream { \exp_not:V\g_presentation_title_tl }
\iow_close:N \g_output_stream
}
\AtEndPreamble{%
\file_if_exist:nTF {\c_sys_jobname_str.sbj} {
\tl_set:Nx \l_tmpa_tl {\file_input:n {\c_sys_jobname_str.sbj}}
\exp_args:NV \title \l_tmpa_tl
}{
\title{No topic!}
}
}
\ExplSyntaxOff
\begin{document}
\maketitle{}
%
\input{topic1}
% \input{topic2}
\input{topic3}
% \input{topic4}
\input{topic5}
\end{document}
答案1
我只需写入辅助文件:
\documentclass{beamer}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{filecontents}
\usepackage[check-declarations]{expl3}
\usepackage{xparse}
\begin{filecontents*}{topic1}
\topictitle{% \TeX{},
\LaTeX{} and café%
}
\begin{frame}
\TeX{}, \LaTeX{} and café are nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic2}
\topictitle{Topic 2}
\begin{frame}
Topic 2 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic3}
\topictitle{Topic 3}
\begin{frame}
Topic 3 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic4}
\topictitle{Topic 4}
\begin{frame}
Topic 4 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic5}
\topictitle{Topic 5}
\begin{frame}
Topic 5 is nice!
\end{frame}
\end{filecontents*}
\ExplSyntaxOn
\seq_new:N \g_topics_seq
\NewDocumentCommand\addtopictitle{m}
{
\seq_gput_right:Nn\g_topics_seq {#1}
}
\makeatletter
\NewDocumentCommand{\topictitle}{m}
{
\iow_now:Nx \@mainaux
{
\exp_not:n {\addtopictitle{#1}}
}
}
\title{\seq_use:Nn\g_topics_seq {,~}}
\ExplSyntaxOff
\begin{document}
\maketitle{}
%
\input{topic1}
% \input{topic2}
\input{topic3}
\input{topic4}
\input{topic5}
\end{document}
答案2
我会按照 Ulrike 的建议去做,写入以\@mainaux
避免污染文件流。我还会避免扩展x
文本(主要是 -type),因为这可能会给你带来麻烦。
还要注意,在您的代码中\tl_set:Nx \l_tmpa_tl {\file_input:n {\c_sys_jobname_str.sbj}}
没有执行任何操作,因为\input
不可扩展,所以您最终得到了\title{\input{\jobname.sbj}}
。
我建议的方法是在文档末尾将 写入\gdef\@input@topics{<stuff>}
,\@mainaux
它将在下次运行中被读取。读取文件后, 就\@input@topics
已经知道了,并且可以简单地在标题中使用。写入的定义必须是全局的,因为文件的内容.aux
是在组内读取的。
在编写步骤中,我使用了e
-type 扩展,\seq_use:Nn
因为x
-type 扩展太多,并且f
-type 会尝试扩展标题的第一个标记,\TeX
除非前面有空格,否则它将扩展。一切都是\exp_not:e
为了避免x
扩展。在以后的运行中,需要\write
一个额外的before ,它已经定义了。\exp_not:N
\@input@topics
代码如下:
\documentclass{beamer}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{filecontents}
\usepackage[check-declarations]{expl3}
\usepackage{xparse}
\begin{filecontents*}{topic1}
\topictitle{\TeX{},
\LaTeX{} and café%
}
\begin{frame}
\TeX{}, \LaTeX{} and café are nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic2}
\topictitle{Topic 2}
\begin{frame}
Topic 2 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic3}
\topictitle{Topic 3}
\begin{frame}
Topic 3 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic4}
\topictitle{Topic 4}
\begin{frame}
Topic 4 is nice!
\end{frame}
\end{filecontents*}
\begin{filecontents*}{topic5}
\topictitle{Topic 5}
\begin{frame}
Topic 5 is nice!
\end{frame}
\end{filecontents*}
\ExplSyntaxOn
\seq_new:N \g_topics_seq
\NewDocumentCommand{\topictitle}{m}
{ \__topic_title:n {#1} }
\cs_new_protected:Npn \__topic_title:n #1
{ \seq_gput_right:Nn \g_topics_seq {#1} }
\makeatletter
\AtEndDocument
{
\iow_now:Nx \@auxout
{
\gdef \exp_not:N \@input@topics
{ \exp_not:e { \seq_use:Nn \g_topics_seq {,~} } }
}
}
\AtBeginDocument
{
\cs_if_exist:NTF \@input@topics
{ \exp_args:NV \title \@input@topics }
{ \title { No~topic! } }
}
\makeatother
\ExplSyntaxOff
\begin{document}
\maketitle{}
%
\input{topic1}
% \input{topic2}
\input{topic3}
% \input{topic4}
\input{topic5}
\end{document}