zref:读出每页的第一个和最后一个参考页

zref:读出每页的第一个和最后一个参考页

我的大多数页面上都有一些段落编号。
如果当前页面包含段落编号 1、2、3,我想在页首写上“(1-3)”。

是否可以读出每页的第一个和最后一个标签页(使用 zref?我真的不了解这个包。)

在此处输入图片描述

\documentclass[fontsize=9pt, paper=a5, 
twoside, numbers=enddot,headsepline,plainheadsepline,
]{scrreprt}

\usepackage{marginnote}

% \usepackage[savepos,totpages,titleref,dotfill,counter,user]{zref} % ?

% Paragraph numbers
\newcounter{parnumber}
\newcommand\parnum[1][\theparnumber]{%
\leavevmode%
\refstepcounter{parnumber}%
\marginnote{\theparnumber\label{pn:#1}}% Label
}

% Layout
\usepackage[automark]{scrlayer-scrpage}[]
\ohead*{\marginnote{(xxx-yyy)}% range of parnums
\ifstr{\headmark}{}{\rightbotmark}{\headmark}% titles in head
}

\usepackage{blindtext}
\begin{document}
\chapter{First Page: The Range of parnums should be (1-3) = (xxx-yyy)}
\parnum[TPy]
Theorem of Pythagoras \par
\parnum
\blindtext  \par

Text without parnum.

\parnum Text.

\chapter{Next Page: The Range of parnums should be (4-5)=(xxx-yyy)}
\parnum Text.

\parnum[mylabel] Text.

\chapter{Only one parnum on this page: The Range of parnums should be (6)=(xxx-yyy)}
\parnum Text.
\end{document}

答案1

下面的代码应该可以满足您的要求(感谢 Ulrike Fischer 的有用评论!)。我使用了(n--p)style 作为范围,但(n-p)如果您愿意,可以很容易地切换到 style 或类似的东西(只需查看\__cis_output_parnum_range:nn:这是对 parnum 信息进行格式化的函数;对于这种更改,应该很容易进行修改)。

\documentclass[fontsize=9pt, paper=a5, twoside, numbers=enddot,
               headsepline,plainheadsepline]{scrreprt}
\usepackage{zref}
\usepackage{multicol}
\usepackage{blindtext}
\usepackage{lipsum}
\usepackage{marginnote}
\usepackage{etoolbox}
\usepackage{xparse}

\ExplSyntaxOn

% ****************************************************************************
% *             LaTeX3 bindings to macros from the zref package              *
% ****************************************************************************

% Extract prop #2 recorded for ref cis-parnum-label-#1 (#1 corresponds to a
% parnum)
\cs_new:Npn \cis_extract_prop:nn #1#2
  {
    % \zref@extract is expandable
    \use:c { zref@extract } { cis-parnum-label-#1 } {#2}
  }

\cs_generate_variant:Nn \cis_extract_prop:nn { V }

\cs_new_protected:Npn \cis_ref_used:n #1
  {
    \use:c { zref@refused } { cis-parnum-label-#1 }
  }

\cs_generate_variant:Nn \cis_ref_used:n { V }

\prg_new_conditional:Npnn \cis_if_parnum_ref_defined:n #1 { p }
  {
    % \zref@ifrefundefined is expandable
    \use:c { zref@ifrefundefined } { cis-parnum-label-#1 }
      { \prg_return_false: }
      { \prg_return_true: }
  }

\prg_generate_conditional_variant:Nnn \cis_if_parnum_ref_defined:n { V } { p }

% ****************************************************************************
% *                Main code for generation of parnum ranges                 *
% ****************************************************************************

% Most important variable: in the \AtBeginDocument hook, we are going to fill
% it to give the parnum range for each page that has at least one parnum. Keys
% in this property list are page numbers (in decimal notation); values have
% the form '{first}{last}' (without quotes). E.g., {2}{5} or {6}{6}. If a page
% contains no parnum at all, the property list will have no key equal to the
% corresponding page number.
\prop_new:N \g_cis_parnums_for_page_prop

\int_new:N \l__cis_fpfep_parnum_int
\int_new:N \l__cis_fpfep_page_in_ref_int
\int_new:N \l__cis_fpfep_last_page_seen_int
\int_new:N \l__cis_fpfep_first_parnum_for_page_int
\int_new:N \l__cis_fpfep_last_parnum_for_page_int

\cs_generate_variant:Nn \int_compare:nNnF { VN }
\cs_generate_variant:Nn \int_compare:nNnF { VNV }

% #1: first labelled parnum in document (if any)
\cs_new_protected:Npn \__cis_find_parnums_for_each_page:n #1
  {
    \int_set:Nn \l__cis_fpfep_parnum_int {#1} % next parnum to examine
    \int_set:Nn \l__cis_fpfep_last_page_seen_int { -1000 } % sentinel value

    \bool_while_do:nn
      { \cis_if_parnum_ref_defined_p:V \l__cis_fpfep_parnum_int }
      {
        % Get the page for parnum \l__cis_fpfep_parnum_int
        \int_set:Nn \l__cis_fpfep_page_in_ref_int
          { \cis_extract_prop:Vn \l__cis_fpfep_parnum_int { page } }
        \cis_ref_used:V \l__cis_fpfep_parnum_int

        \int_compare:VNVF
          \l__cis_fpfep_last_page_seen_int = \l__cis_fpfep_page_in_ref_int
          {
            % The parnum corresponding to the currently examined ref is on a
            % different page than the previously-examined parnum, therefore
            % we now have all the info for the last seen page -> store it.
            \__cis_store_parnums_if_real_page:VVV
              \l__cis_fpfep_last_page_seen_int
              \l__cis_fpfep_first_parnum_for_page_int
              \l__cis_fpfep_last_parnum_for_page_int

            \int_set_eq:NN \l__cis_fpfep_first_parnum_for_page_int
                           \l__cis_fpfep_parnum_int
          }

        % Will be overwritten if there are more parnums on the same page
        \int_set_eq:NN \l__cis_fpfep_last_parnum_for_page_int
                       \l__cis_fpfep_parnum_int
        \int_set_eq:NN \l__cis_fpfep_last_page_seen_int
                       \l__cis_fpfep_page_in_ref_int
        \int_incr:N \l__cis_fpfep_parnum_int
      }

    % Store info for the last page containing a labelled parnum
    \__cis_store_parnums_if_real_page:VVV
      \l__cis_fpfep_last_page_seen_int
      \l__cis_fpfep_first_parnum_for_page_int
      \l__cis_fpfep_last_parnum_for_page_int
  }

% #1: page number or sentinel value (-1000) meaning “do nothing”
% #2: first parnum on this page
% #3: last parnum on this page
\cs_new_protected:Npn \__cis_store_parnums_if_real_page:nnn #1#2#3
  {
    \int_compare:nNnF {#1} = { -1000 }
      {
        \prop_gput:Nnn \g_cis_parnums_for_page_prop {#1} { {#2} {#3} }
      }
  }

\cs_generate_variant:Nn \__cis_store_parnums_if_real_page:nnn { VVV }
\cs_generate_variant:Nn \__cis_output_parnum_range:nn { VV }

\tl_new:N \g__cis_oprfp_first_parnum_tl
\tl_new:N \g__cis_oprfp_last_parnum_tl

\cs_new_protected:Npn \cis_output_parnums_range_for_page:n #1
  {
    \prop_get:NnNTF \g_cis_parnums_for_page_prop {#1} \l_tmpa_tl
      {
        \seq_set_split:NnV \l_tmpa_seq { } \l_tmpa_tl
        \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
        \seq_pop_left:NN \l_tmpa_seq \l_tmpb_tl

        \tl_gset_eq:NN \g__cis_oprfp_first_parnum_tl \l_tmpa_tl
        \tl_gset_eq:NN \g__cis_oprfp_last_parnum_tl \l_tmpb_tl
        \__cis_output_parnum_range:VV \g__cis_oprfp_first_parnum_tl
                                      \g__cis_oprfp_last_parnum_tl
      }
      {
        % In case there is no parnum at all on a page, the OP wants the page
        % header to hold only the last parnum seen (not the last parnum info,
        % i.e.: he wants only a number, not a range). Hence "last, last"
        % instead of "first, last" here:
        \__cis_output_parnum_range:VV \g__cis_oprfp_last_parnum_tl
                                      \g__cis_oprfp_last_parnum_tl
      }
  }

% Write formatted information for the specified parnum range.
%
% #1: first parnum of range
% #2: last parnum of range
\cs_new_protected:Npn \__cis_output_parnum_range:nn #1#2
  {
    \tl_if_eq:nnTF {#1} {#2}
      {
        \tl_if_blank:nF {#1} { (#1) }
      }
      {
        (#1--#2)
      }
  }

\cs_generate_variant:Nn \cis_output_parnums_range_for_page:n { x }

% Fully expands the argument (which should be a page number)
\NewDocumentCommand \parnumrangeinpage { m }
  {
    \cis_output_parnums_range_for_page:x {#1}
  }

% 1 is the number of the first parnum to consider as possibly existing in the
% document. \__cis_find_parnums_for_each_page:n looks for refs corresponding
% to parnums 1, 2, ... The smallest integer in this scanning process for which
% no ref is found in the .aux file is considered to be one past the last
% parnum.
\AtBeginDocument { \__cis_find_parnums_for_each_page:n { 1 } }

\ExplSyntaxOff

\makeatletter

\zref@newlist{cisparnumlist}
\zref@addprop{cisparnumlist}{page}

% Paragraph numbers. Must be strictly increasing, and the numbering should
% have no holes.
\newcounter{parnumber}

\newcommand*\parnum[1][]{%
  \leavevmode
  \refstepcounter{parnumber}%
  \ifblank{#1}{}{\label{#1}}% regular LaTeX label for the numbered paragraph
  \marginnote{%
    \theparnumber
    % Set our special zref label for parnums. From the set of all such labels,
    % we can deduce in the \AtBeginDocument hook the parnum range for each
    % page.
    \zref@labelbylist{cis-parnum-label-\the\value{parnumber}}%
                     {cisparnumlist}}%
}

\makeatother

% Allow easy on/off switching of parnum info in headers
\newtoggle{parnumsinheader}

\newcommand*{\parnumsinheaderon}{\toggletrue{parnumsinheader}}
\newcommand*{\parnumsinheaderoff}{\togglefalse{parnumsinheader}}

\parnumsinheaderon              % Show parnum info in headers by default

% Set up the page headers
\usepackage[automark]{scrlayer-scrpage}
\ohead*{%
  \iftoggle{parnumsinheader}{%
    \marginnote{\parnumrangeinpage{\thepage}}% range of parnums
  }{}%
  \ifstr{\headmark}{}{\rightbotmark}{\headmark}% chapter or section title, etc.
}

\begin{document}

\chapter{Three parnums here}

\parnum[TPy]
Theorem of Pythagoras \par
\parnum
\blindtext  \par

Text without parnum.

\parnum Text.

The theorem of Pythagoras corresponds to parnum~\ref{TPy} on
page~\pageref{TPy}.

\chapter{Two parnums here}

\parnum Text.

\parnum[mylabel] Text.

\chapter{Only one parnum here}

\parnum Text.

\newpage % Test repeating of last parnum info when there is no parnum on the
         % current page.
\chapter{Test with parnums deeply embedded in \TeX\ lists}

\noindent
{\centering
\begin{minipage}{\linewidth}
\begin{multicols}{2}
  \parnum Text.

  \lipsum[1-3]

  \parnum Text.
\end{multicols}
\end{minipage}
}
\newpage
\lipsum[1-2]

\end{document}

第 1 页


第2页


第 3 页


第 4 页


第 5 页


第 6 页

相关内容