10 如何将/pageref{here}label{here}得到的页码输出到外部文件中

发布于 2021-12-09 18:39:15

命令/pageref{here}label{here}可以打印出当前位置的所在页码,命令运行时可以直接在latex上渲染出来,现在我想把pageref{here}label{here}得到的页码写入到另外的txt文件中去,但是直接运行会报错,代码如下

\documentclass{article}

\usepackage{zref-abspage,lipsum}

\usepackage{fancyhdr}

\newwrite\myoutfile

\immediate\openout\myoutfile=\jobname-myoutfile.txt

\begin{document}

\lipsum[1-10]

\immediate\write\myoutfile{\pageref{here}\label{here}.}

\lipsum[10-12]

\end{document}

查看更多

关注者
0
被浏览
282
雾月
雾月 2021-12-09

简单来说,当 label 不存在时,强行展开 \pageref 就会出现该错误。
第一次运行时,label 还没有写入 aux,这时,由于 \write 会自动展开它的参数,于是就出错了。

知道这之后,就容易解决了。

% \usepackage{expl3}% 在较新的 LaTeX2e 中是不必要的
\makeatletter
\ExplSyntaxOn
\cs_if_free:NT \use_ii:nnnnn
  { \cs_new:Npn \use_ii:nnnnn #1#2#3#4#5 { #2 } }
% 使用 hyperref,`\newlabel` 会写入 5 个参数,不使用 hyperref,则会写入 2 个参数,需要分别处理
% 第二个参数就是 page
\@ifpackageloaded{hyperref}
  {
    \cs_set_nopar:Npn \getrefpage #1
      { % 判断 label 是否存在,LaTeX 使用 "r@<label>" 保存 label
        \cs_if_exist:cTF { r@#1 } 
          { \exp_last_unbraced:Nv \use_ii:nnnnn { r@#1 } } % 获得5个中的第2个
          { 0 } % 若不存在则使用 0
      }  
  }
  {
    \cs_set_nopar:Npn \getrefpage #1
      { % 同上
        \cs_if_exist:cTF { r@#1 } 
          { \exp_last_unbraced:Nv \use_ii:nn { r@#1 } } 
          { 0 }
      }
  }
\ExplSyntaxOff
\makeatother

这样我们就可以使用 \getrefpage{<label>} 来获取 \label 定义的 label 的页码

\immediate\write\myoutfile{\getrefpage{nohere:a}}
\label{nohere:a} % label 需要在 \write 外部,才能创造一个label

由于 \label 是不可扩展的,若要在 \write 中写入,则需要使用 \noexpand\string

\immediate\write\myoutfile{\getrefpage{nohere:a}\noexpand\label{nohere:a}}
\label{nohere:a}

另外,\label 中的 page 实际上是 \thepage 而不是绝对页码,也不一定是数字,例如修改了 page 计数器,或者使用了 \pagenumbering

此时,要想获得绝对页面,可以使用 zref-abspage 宏包,相应的,可以定义一个 \getzrefabspage\getzrefpage 来获得绝对页码和相对页码。

% \usepackage{zref-abspage}
\makeatletter
\def\getzrefabspage#1{\zref@extract{#1}{abspage}}
\def\getzrefpage#1{\zref@ifrefundefined{#1}{0}{\zref@extract{#1}{page}}} % 同样需要检查是否存在
\makeatother
% \usepackage{zref-user,zref-abspage}
\zlabel{here:a}% 使用 \zlabel 而不是 \label
\immediate\write\myoutfile{\getzrefpage{here:a}\noexpand\zlabel{here:a}}
\immediate\write\myoutfile{\getzrefabspage{here:a}\noexpand\zlabel{here:a}}

当修改了 page 计数器,或者使用了 \pagenumbering 时,这二者是不同的。

一个完整的例子:

\documentclass{article}
% \usepackage{expl3}
\usepackage{zref-user,zref-abspage,lipsum}

\newwrite\myoutfile
\immediate\openout\myoutfile=\jobname-myoutfile.txt

\makeatletter
\def\getzrefabspage#1{\zref@extract{#1}{abspage}}
\def\getzrefpage#1{\zref@ifrefundefined{#1}{0}{\zref@extract{#1}{page}}}
\ExplSyntaxOn
\cs_if_free:NT \use_ii:nnnnn
  { \cs_new:Npn \use_ii:nnnnn #1#2#3#4#5 { #2 } }
\@ifpackageloaded{hyperref}
  {
    \cs_set_nopar:Npn \getrefpage #1
      {
        \cs_if_exist:cTF { r@#1 } 
          { \exp_last_unbraced:Nv \use_ii:nnnnn { r@#1 } } 
          { 0 }
      }  
  }
  {
    \cs_set_nopar:Npn \getrefpage #1
      {
        \cs_if_exist:cTF { r@#1 } 
          { \exp_last_unbraced:Nv \use_ii:nn { r@#1 } } 
          { 0 }
      }
  }
\ExplSyntaxOff
\makeatother

\begin{document}

\immediate\write\myoutfile{\getzrefpage{here:a}\noexpand\zlabel{here:a}}
\immediate\write\myoutfile{\getzrefabspage{here:a}\noexpand\zlabel{here:a}}
\zlabel{here:a}

\immediate\write\myoutfile{\getrefpage{nohere:a}\noexpand\label{nohere:a}}
\label{nohere:a}


\lipsum[1-10]


\pagenumbering{alph}


\zlabel{here:b}.
\immediate\write\myoutfile{\getzrefpage{here:b}\noexpand\zlabel{here:b}}
\immediate\write\myoutfile{\getzrefabspage{here:b}\noexpand\zlabel{here:b}}


\label{nohere:b}.
\immediate\write\myoutfile{\getrefpage{nohere:b}\noexpand\label{nohere:b}}

\lipsum[10-12]

\end{document}

在较新的 LaTeX2e 发行版中,原生提供了 \ReadonlyShipoutCountertotalpages 计数器来记录绝对页码。

1 个回答

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览