最小工作示例

最小工作示例

由于需要处理大量的页面范围,我希望有一个强大而简单的命令可以正确地解析和打印它们。

  1. 最简单的情况是

    264,15-26

    意思是:

    第 264 页,第 15 至 26 行

  2. 然后我们就有了类似

    264,15-266,26

    也就是说

    第 264 页第 15 行至第 266 页第 26 行

  3. 更棘手的是,我们会得到类似

    264,15-266,26+277,13-14+312,14-316,23

    这意味着我们实际上这里有三个序列:

    从第 264 页第 15 行到第 266 页第 26 行和第 277 页第 13-14 行以及从第 312 页第 14 行到第 316 页第 23 行

    也就是说,无论提供多少“类型 1”或“类型 2”序列,命令都应该起作用。

我想将页面范围(类型 1 或 2 或 3)放在一个命令中,然后以可读和准确的方式打印其中的每一个......对于像我这样可怜的老人文学生来说,这相当棘手!

答案1

这是一个 LuaLaTeX 解决方案:

最小工作示例

\documentclass{article}
\directlua{dofile("parse.lua")}
\def\parserange#1{\directlua{tex.sprint(parsePageRanges("#1"))}}
\begin{document}

\begin{itemize}
\item \parserange{264,15-26}
\item \parserange{264,15-266,26}
\item \parserange{264,15-266,26+277,13-14+312,14-316,23}
\end{itemize}
\end{document}

结果

结果

Lua 代码

保存在文件中parse.lua

function split(text, sep)
    sep = sep or "\n"
    local lines = {}
    local pos = 1
    while true do
        local b,e = text:find(sep, pos)
        if not b then table.insert(lines, text:sub(pos)) break end
        table.insert(lines, text:sub(pos, b-1))
        pos = e + 1
    end
    return lines
end

function parsePageRanges(s)
    ranges=split(s, "+")
    parsed_ranges = {}
    for i,range in ipairs(ranges) do
         ends = split(range, "-")
         if #ends ~=2 then
             return("Error in page range ``"..range.."''")
         end
         r={}
         r[1] = split(ends[1], ",")
         r[2] = split(ends[2], ",")
         if #r[2]==1 then
             p1=r[1][1]; l1=r[1][2]; l2=r[2][1]
             table.insert(parsed_ranges, "page "..p1..", lines "..l1.." to "..l2)
         else
             p1=r[1][1]; l1=r[1][2]; p2=r[2][1]; l2=r[2][2]
             table.insert(parsed_ranges, "from page "..p1.." line "..l1.." to page "..p2.." line "..l2)
         end
    end
    return table.concat(parsed_ranges, " and ")
end

答案2

这是一个 LaTeX3 的实现。

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn

\NewDocumentCommand{\parsepages}{m}
 {
  \pierre_parse_pages:n { #1 }
 }

\seq_new:N \l_pierre_blocks_seq
\seq_new:N \l_pierre_output_seq
\seq_new:N \l_pierre_temp_seq

\cs_new_protected:Npn \pierre_parse_pages:n #1
 {
  % decompose the argument into blocks delimited by +
  \seq_set_split:Nnn \l_pierre_blocks_seq { + } { #1 }
  \seq_clear:N \l_pierre_output_seq
  % process each block
  \seq_map_inline:Nn \l_pierre_blocks_seq
   {
    \pierre_parse_block:n { ##1 }
   }
  % print the result
  \seq_use:Nnnn \l_pierre_output_seq {~and~} {~and~} {~and~}
 }

\cs_new_protected:Npn \pierre_parse_block:n #1
 {
  \tl_if_in:nnTF { #1 } { - }
   {% we have a "complex block"; either a,b-c,d or a,b-c
    \pierre_parse_complex_block:n { #1 }
   }
   {% a "simple block" a,b
    \pierre_parse_simple_block:w #1 \q_stop
   }
 }

\cs_new_protected:Npn \pierre_parse_simple_block:w #1 , #2 \q_stop
 {
  \seq_put_right:Nn \l_pierre_output_seq
   {
    page~#1~line~#2
   }
 }

\cs_new_protected:Npn \pierre_parse_complex_block:n #1
 {
  \seq_set_split:Nnn \l_pierre_temp_seq { , } { #1 }
  \int_compare:nTF { \seq_count:N \l_pierre_temp_seq = 2 }
   {% only one comma: a,b-c
    \pierre_single_page:w #1 \q_stop
   }
   {% two commas: a,b-c,d
    \pierre_multi_page:w #1 \q_stop
   }
 }

\cs_new_protected:Npn \pierre_single_page:w #1 , #2 - #3 \q_stop
 {
  \seq_put_right:Nn \l_pierre_output_seq
   {
    page~#1~lines~#2~to~#3
   }
 }

\cs_new_protected:Npn \pierre_multi_page:w #1 , #2 - #3 , #4 \q_stop
 {
  \seq_put_right:Nn \l_pierre_output_seq
   {
    from~page~#1~line~#2~to~page~#3~line~#4
   }
 }
\ExplSyntaxOff

\begin{document}

% just for formatting the example
\setlength{\parindent}{0pt}
\setlength{\parskip}{1ex}

\parsepages{264,15}

\parsepages{264,15-26}

\parsepages{264,15-266,26}

\parsepages{264,15-266,26+277,13-14+312,14-316,23}

\end{document}

在此处输入图片描述

答案3

pdflatex带有软件包的解决方案listofitems

修改后的答案

我担心我原来的回答(如下)误解了何时应插入“from”的上下文。在此修订中,当序列的范围跨越页面边界时,将应用“from”。

\documentclass{article}
\usepackage{listofitems}
\newcommand\parsepages[1]{\bgroup%
  \def\+{ and }%
  \def\-{ to }%
  \def\,{, line\checkplural{} }%
  \setsepchar{+/-/,}%
  \readlist*\mypages{#1}%
  \foreachitem\i\in\mypages[]{%
    \foreachitem\j\in\mypages[\icnt]{%
      \foreachitem\k\in\mypages[\icnt,\jcnt]{%
        \ifnum\kcnt<\listlen\mypages[\icnt,\jcnt]\relax\checkpages page \fi%
        \k \ifnum\kcnt<\listlen\mypages[\icnt,\jcnt]\relax
             \csname\mypagessep[\icnt,\jcnt,\kcnt]\endcsname \fi%
      }\ifnum\jcnt<\listlen\mypages[\icnt]\relax%
         \csname\mypagessep[\icnt,\jcnt]\endcsname\fi%
    }\ifnum\icnt<\listlen\mypages[]\relax\csname\mypagessep[\icnt]\endcsname\fi%
  }%
\egroup}
\newcommand\checkplural{\ifnum\numexpr\jcnt+1=\listlen\mypages[\icnt]\relax%
  \ifnum\kcnt=\listlen\mypages[\icnt,\numexpr\jcnt+1]\relax s\fi\fi}
\newcommand\checkpages{\ifnum\jcnt=\listlen\mypages[\icnt]\relax\else%
  \ifnum\listlen\mypages[\icnt,\the\numexpr\jcnt+1\relax]>1\relax from \fi\fi}
\begin{document}
\begin{enumerate}
\item \verb|\parsepages{264,15-26}|\par
\parsepages{264,15-26}
\item \verb|\parsepages{264,15-266,26}|\par
\parsepages{264,15-266,26}
\item\verb|\parsepages{264,15-266,26+277,13-14+312,14-316,23}|\par
\parsepages{264,15-266,26+277,13-14+312,14-316,23}
\end{enumerate}
\end{document}

在此处输入图片描述

原始答案

在此答案中,当答案涉及多个序列时,会插入“from”。然后,“from”应用于第一个和最后一个序列。

\documentclass{article}
\usepackage{listofitems}
\newcommand\parsepages[1]{%
  \def\+{ and \checkfrom}%
  \def\-{ to }%
  \def\,{, line\checkess{} }
  \setsepchar{+/-/,}
  \readlist*\mypages{#1}%
  \foreachitem\i\in\mypages[]{%
    \ifnum\listlen\mypages[]>1\relax%
      \ifnum\icnt=1\relax from \fi\fi%
    \foreachitem\j\in\mypages[\icnt]{%
      \foreachitem\k\in\mypages[\icnt,\jcnt]{%
        \ifnum\kcnt<\listlen\mypages[\icnt,\jcnt]\relax%
           page %
        \fi%
        \k \ifnum\kcnt<\listlen\mypages[\icnt,\jcnt]\relax
           \csname\mypagessep[\icnt,\jcnt,\kcnt]\endcsname \fi%
      }\ifnum\jcnt<\listlen\mypages[\icnt]\relax%
         \csname\mypagessep[\icnt,\jcnt]\endcsname\fi%
    }\ifnum\icnt<\listlen\mypages[]\relax%
       \csname\mypagessep[\icnt]\endcsname\fi%
  }%
}
\newcommand\checkfrom{\ifnum\numexpr\icnt+1=\listlen\mypages[]\relax from \fi}
\newcommand\checkess{\ifnum\numexpr\jcnt+1=\listlen\mypages[\icnt]\relax%
  \ifnum\kcnt=\listlen\mypages[\icnt,\numexpr\jcnt+1]\relax s\fi\fi}
\begin{document}
\begin{enumerate}
\item \verb|\parsepages{264,15-26}|\par
\parsepages{264,15-26}
\item \verb|\parsepages{264,15-266,26}|\par
\parsepages{264,15-266,26}
\item\verb|\parsepages{264,15-266,26+277,13-14+312,14-316,23}|\par
\parsepages{264,15-266,26+277,13-14+312,14-316,23}
\end{enumerate}
\end{document}

在此处输入图片描述

相关内容