lastpage 包用于获取到文档的总页数,其原理是通过 LaTeX 提供的 hook \AtEndDocumnet
命令,在 \end{document}
之前去获取最后一页的页码计数器的值,并保存在一个命令里面,然后前文使用这个命令就能得到这个值
大致思路是这样,我们可以在导言区写道:
\AtEndDocument{
\def\lastpage{\thepage}
}
然后在前文使用 \lastpage
, 很遗憾,会报错(
command lastpage undefined
, 因为 tex 程序是从前往后运行的,也就是说,\lastpage
定义在后,使用在前. 解决这个问题,我们需要将定义内容写到外部文件中,然后在导言区 \input
这个文件.\def\lastpage{\thepage}
然后在导言区引入,无异于直接在导言区写道 \def\lastpage{\thepage}
, 也就是说你在文档中写下 \lastpage
,无异于直接写 \thepage
,并不会得到最后一页的页码\def
改为 \xdef
,区别在于 \xedf
会将 \thepage
展开,而 \def
只是简单的宏替换\documentclass{article}
\ExplSyntaxOn
\iow_new:N \l_lastpage_file
\file_if_exist:nTF{\c_sys_jobname_str.page}
{
\file_input:n{\c_sys_jobname_str.page}
}
{
\cs_set_eq:NN \lastpage \relax
}
\AtEndDocument{
\iow_open:Nn \l_lastpage_file{\c_sys_jobname_str.page}
\iow_now:Nx \l_lastpage_file
{
\cs_set:Npn \exp_not:N \lastpage
{
\thepage
}
}
\iow_close:N \l_lastpage_file
}
\ExplSyntaxOff
\begin{document}
aaa \lastpage
\newpage
bbb
\newpage
ccc
\newpage
ddd
\end{document}
原谅我使用了 LaTeX3,代码后面再来解读,先去上课了...
注意到下面的代码
\iow_new:N \l_lastpage_file
\AtEndDocument{
\iow_open:Nn \l_lastpage_file{\c_sys_jobname_str.page}
\iow_now:Nx \l_lastpage_file
{
\cs_set:Npn \exp_not:N \lastpage
{
\thepage
}
}
\iow_close:N \l_lastpage_file
}
第一行 \iow_new:N \l_lastpage_file
是新建一个文件写入流,第三行 \iow_open:Nn \l_lastpage_file{\c_sys_jobname_str.page}
是打开这个写入流,并写入 <当前项目名.page>
这个文件中.
\iow_now:Nx \l_lastpage_file
{
\cs_set:Npn \exp_not:N \lastpage
{
\thepage
}
}
用于在文件中写入内容. 写入的内容相当于前文中提到的 \xdef\lastpage{\thepage}
.\iow_close:N \l_lastpage_file
用于关闭这个写入流.
运行后文件夹中就会出现一个 xxx.page
的文件,内容是:
\cs_set:Npn \lastpage {<最后一页的页码值>} %相当于 \xdef\lastpage{<最后一页的页码值>}
如果我们直接在导言区写道 \input{xxx.page}
会有问题,因为第一次编译的时候 LaTeX 运行到该行的时候,该文件还没有生成. 自然会报错,文件没写入, 也意味着 \lastpage
命令还没定义.
解决这个问题如下写法:
\file_if_exist:nTF{\c_sys_jobname_str.page}
{
\file_input:n{\c_sys_jobname_str.page}
}
{
\cs_set_eq:NN \lastpage \relax
}
判断一下文件是否存在,如果存在就导入,不存在就先初始化一下 \lastpage
命令,避免出现未定义的报错.