正如下面的 MCE 所指出的,一个用于expl3
存储结果的标记列表变量\seq_map_inline:
\title
的参数
- 就像一个魅力
article
, 不适用于以下
beamer
课程:! Undefined control sequence. <argument> \LaTeX3 error: A sequence was misused.
您知道为什么以及如何使它与beamer
的类一起工作吗?
% \documentclass{article}
\documentclass{beamer}
\usepackage{xparse}
\ExplSyntaxOn
\seq_gset_from_clist:Nn \g_tmpa_seq { foo, bar }
\tl_set:Nn \g_tmpa_tl
{
\seq_map_inline:Nn \g_tmpa_seq
{
#1,\c_space_tl
}
}
\title{\g_tmpa_tl}
\ExplSyntaxOff
\begin{document}
\maketitle
\end{document}
编辑:目标引导我提出当前的问题(及其简化的 MCE)
对于我开设的一门课程,我会为全班准备一些演示文稿beamer
(顺便说一句,以下内容适用于任何课程)。整个课程的内容分为几个主题(每个主题一个文件)\input
。可以处理的主题(标题)/相应文件如下:
- “Foo 1”/
foo1.tex
- “Foo 2”/
foo2.tex
- “Foo 3”/
foo3.tex
- “Foo 4”/
foo4.tex
- “Foo 5”/
foo5.tex
演示的内容(选定的主题)根据听众和/或课程进度而有所不同。
重点是,我希望对于给定的演示文稿,所选主题的标题出现在演示文稿的\title
。
假设当前演示的是“Foo 2”和“Foo 4”。我可以执行以下操作:
\documentclass{beamer}
...
\title{
% Foo 1,
Foo 2,
% Foo 3,
Foo 4
% Foo 5,
}
\begin{document}
\maketitle
% \input{foo1}
\input{foo2}
% \input{foo3}
\input{foo4}
% \input{foo5}
\end{document}
但这种方式很痛苦,而且容易出错:每当 ed 文件列表
\input
发生变化时,我必须(不要忘记)更改\title
的内容。
请注意,在相应的文件中包含主题的标题是没有意义的:它们太晚被读取而无法被放入演示文稿中\title
(好吧,另一种方法是将它们写入.aux
文件中,然后在下一次编译时读取它们,当\title
必须填充,但那是另一个故事)。
因此,我的目标是:
- 固定的房产清单(比如说
\g_subjects_prop
)包含所有主题的完整列表,每个主题都有:- key:对应文件的名称,
- 作为值:其标题。此列表可以通过文档命令(例如
SubjectFileTitle{⟨filename⟩}{⟨title⟩}
)填充到配置文件中,
- A顺序(例如
\g_chosen_subjects_seq
)包含所选主题的键。此序列可以通过文档命令(例如ChosenSubjects{⟨comma separated list of keys (files)⟩}
)填充到序言中, - 一个标记列表(例如
\g_title_tl
,而不是\l_tmpa_tl
(?)),其中包含与上面选择的键相对应的值,这些值将作为\title
的参数传递, - 一个文档命令(比如),当使用时,它会插入所选文件
\InputChosenSubjects
的序列。\input
感谢 egreg 的回答,我使用以下代码进行了处理:
\begin{filecontents*}{foo2}
\begin{frame}
\frametitle{Foo 2 subject: quite interesting!}
...
\end{frame}
\end{filecontents*}
\documentclass{beamer}
\usepackage{xparse}
\ExplSyntaxOn
\prop_new:N \g_subjects_prop
\seq_new:N \g_chosen_subjects_seq
\tl_new:N \g_title_tl
\NewDocumentCommand{\SubjectFileTitle}{mm}
{
\prop_gput:Nnn \g_subjects_prop {#1} {#2}
}
\cs_new_protected:Npn \__chosen_subjects:n #1
{
\seq_gset_from_clist:Nn \g_chosen_subjects_seq {
#1
}
\seq_map_inline:Nn \g_chosen_subjects_seq
{
\prop_get:NnN \g_subjects_prop {##1} \l_tmpa_tl
\tl_if_empty:NF \l_tmpa_tl {
\seq_put_right:Nn \g_tmpa_seq {\prop_item:Nn \g_subjects_prop {##1}}
}
}
\tl_gset:Nx \g_title_tl
{
\seq_use:Nn \g_tmpa_seq {,~}
}
\title{\g_title_tl}
}
\NewDocumentCommand{\ChosenSubjects}{m}
{
\__chosen_subjects:n {#1}
}
\cs_new_protected:Npn \__input_chosen_subjects_files:
{
\seq_map_inline:Nn \g_chosen_subjects_seq
{
\par
\file_if_exist_input:nF {##1}{%
\begin{frame}
\frametitle{\alert{File~\texttt{##1.tex}~not~found!}}
\end{frame}
}
}
}
\NewDocumentCommand{\InputChosenSubjects}{}{
\__input_chosen_subjects_files:
}
\ExplSyntaxOff
\SubjectFileTitle{foo1}{Foo 1}
\SubjectFileTitle{foo2}{Foo 2}
\SubjectFileTitle{foo3}{Foo 3}
\SubjectFileTitle{foo4}{Foo 4}
\SubjectFileTitle{foo5}{Foo 5}
\ChosenSubjects{
% foo1,
foo2,
% foo3,
foo4,
% foo5,
}
\begin{document}
\maketitle{}
\InputChosenSubjects
\end{document}
答案1
你要求 TeX\seq_map_inline:Nn
在处理 时执行\maketitle
。更可能的情况是,你想\maketitle
打印用“逗号和空格”分隔的单词列表。为此,请使用\tl_gset:Nx
和\seq_use:Nn
。
\documentclass{beamer}
\usepackage{xparse}
\ExplSyntaxOn
\seq_gset_from_clist:Nn \g_tmpa_seq { foo, bar }
\tl_gset:Nx \g_tmpa_tl
{
\seq_use:Nn \g_tmpa_seq {,~}
}
\exp_args:NV \title \g_tmpa_tl
\ExplSyntaxOff
\begin{document}
\maketitle
\end{document}
我注意到这\g_tmpa_tl
不是适合使用的变量,但我相信这只是为了举例子。
这是您代码的编辑版本。我重命名了函数和变量,并赋予了通用前缀。最重要的是,我修复了一个问题:如果变量中不存在某个属性prop
,那么
\prop_get:NnN <prop variable> {<property>} <tl variable>
将标记列表变量设置为\q_no_value
,而不是“空”。因此要使用的测试是\quark_if_no_value:NF
。
另外,\title{\g_pres_title_tl}
我宁愿
\exp_args:NV \title \g_pres_title_tl
因此变量的内容被传递给\title
,而不是容器。
\begin{filecontents*}{foo2}
\begin{frame}
\frametitle{Foo 2 subject: quite interesting!}
...
\end{frame}
\end{filecontents*}
\documentclass{beamer}
\usepackage{xparse}
\ExplSyntaxOn
%% variables
\prop_new:N \g_pres_subjects_prop
\seq_new:N \g_pres_subjects_chosen_seq
\tl_new:N \g_pres_title_tl
%% User level commands
\NewDocumentCommand{\SubjectFileTitle}{mm}
{
\prop_gput:Nnn \g_pres_subjects_prop {#1} {#2}
}
\NewDocumentCommand{\ChosenSubjects}{m}
{
\pres_subjects_choose:n {#1}
}
\NewDocumentCommand{\InputChosenSubjects}{}
{
\pres_input_chosen_subjects_files:
}
%% functions
\cs_new_protected:Npn \pres_subjects_choose:n #1
{
\seq_gset_from_clist:Nn \g_pres_subjects_chosen_seq { #1 }
\seq_map_inline:Nn \g_pres_subjects_chosen_seq
{
\prop_get:NnN \g_pres_subjects_prop {##1} \l_tmpa_tl
\quark_if_no_value:NF \l_tmpa_tl
{
\seq_put_right:NV \l_tmpa_seq \l_tmpa_tl
}
}
\tl_gset:Nx \g_pres_title_tl
{
\seq_use:Nn \l_tmpa_seq {,~}
}
\exp_args:NV \title \g_pres_title_tl
}
\cs_new_protected:Npn \pres_input_chosen_subjects_files:
{
\seq_map_inline:Nn \g_pres_subjects_chosen_seq
{
\par
\file_if_exist_input:nF {##1}
{
\begin{frame}
\frametitle{\alert{File~\texttt{##1.tex}~not~found!}}
\end{frame}
}
}
}
\ExplSyntaxOff
\SubjectFileTitle{foo1}{Foo 1}
\SubjectFileTitle{foo2}{Foo 2}
\SubjectFileTitle{foo3}{Foo 3}
\SubjectFileTitle{foo4}{Foo 4}
\SubjectFileTitle{foo5}{Foo 5}
\ChosenSubjects{
% foo1,
foo2,
% foo3,
foo4,
% foo5,
blurb % this doesn't exist among the defined files
}
\begin{document}
\maketitle{}
\InputChosenSubjects
\end{document}
答案2
评论太长,如果没有 beamer 也会出现同样的错误
\documentclass{article}
\usepackage{hyperref}
\usepackage{xparse}
\ExplSyntaxOn
\seq_gset_from_clist:Nn \g_tmpa_seq { foo, bar }
\tl_set:Nn \g_tmpa_tl
{
\seq_map_inline:Nn \g_tmpa_seq
{
#1,\c_space_tl
}
}
\newcommand\test[1]{
\def\inserttest{#1}
}
\test{\g_tmpa_tl}
\ExplSyntaxOff
\begin{document}
%\maketitle
\hypersetup{pdftitle=\inserttest}
test
\end{document}
答案3
beamer 问题 (在 beamerbasetitle.sty 中)
\hypersetup{pdftitle={\inserttitle\ifx\insertsubtitle\@empty\else\ - \insertsubtitle\fi}}
这意味着 \inserttitle 应该是 hyperref 可以在书签中处理的内容——当涉及到 expl3 命令时:坚持使用文档中带有星号的命令。
您可以使用以下方式避免 beamer 使用 pdftitle 作为标题
\documentclass[usepdftitle=false,hyperref={pdftitle=somethingsafe}]{beamer}
这也会影响作者的 pdf 字段,因此也需要手动设置。