对于一本每日灵修的书,我根本没有页码,但每个部分对应一年中的一天,每页一天。我在书的末尾生成一个圣经参考文献索引,并将圣经参考文献链接到引用它们的页面。但由于书中没有页码,索引必须包含日期(即部分,例如“13 Mai”而不是 151)而不是页码。
到目前为止,我的(丑陋的)解决方案是在日志中使用以下命令输出部分名称和页面:
\typeout{Date on page \thepage:\thesection:\chaphead}%
然后使用 shell 脚本解析日志并使用 sed 修改生成的索引(.ind 文件):
#!/bin/bash
NAME="$1"
while read -r page day month; do
bsmonth=$(sed -e 's@\\@\\\\@g' <<<$month)
sed -i "s@textrm{\([^,]*, \)\?$page\(, [^,]*\)\?}@textrm{\1\\\\hyperlink{page.$page}{\\\\mbox{\\\\scshape\\\\makedate{$day}~$bsmonth}}\2}@g" $NAME.ind
done < <(sed -n 's@Date on page \([0-9]\+\):\([0-9]\+\):\(.*\)@\1 \2 \3@p' $NAME.log)
我会这样调用 LaTeX:
%.pdf: %.tex
TEXINPUTS=$(TEXINPUTS) pdflatex -shell-escape -interaction=batchmode $<
# Modify index to use dates instead of pages
./index_dates.sh $*
# No -shell-escape to prevent re-creation of index
TEXINPUTS=$(TEXINPUTS) pdflatex -interaction=batchmode $<
我正在使用imakeidx
,因此在编译文档时索引会自动重新生成。在 TeXLive 2009 中,不传递-shell-escape
会阻止imakeidx
重建索引,从而阻止擦除所做的更改index_dates.sh
,因此它工作正常(尽管仍然很丑陋)。
现在在 TeXLive 2010 中,这个-shell-escape
技巧不起作用了,在我切换到另一个丑陋的技巧之前,我想考虑用正确的 TeX 重写这段代码。你能给我一些提示,告诉我如何正确地做到这一点吗?
我应该生成如下动态宏吗:
\def\pagemonth@\csname \thepage{\thesection~\chaphead}
然后修改索引?如果是的话,我该如何修改索引?
我是否应该将这些宏写入单独的文件并稍后导入它(以及如何做到这一点)?
我应该加入吗
imakeidx
(以及如何加入)?我是否应该
imakeidx
用另一个可以更容易实现这一点的包来替换它?我是否应该切换到另一个索引生成器(例如
xindy
)并且我应该向它传递哪些参数?我是否应该为索引中的页码添加“样式”,这实际上是对用我的内容替换的宏的调用?
答案1
这是一个可能的解决方案。我分部分展示,应该很容易适应您的设置。
(1)我定义一个计数器,并在每次使用命令启动新的部分时对其进行步进\Section
,该命令定义一个唯一的命令,保存该部分的标题,其名称取决于计数器的值。
(2) 我获取相关索引命令的副本并对其进行修补:\Index
requires\@Index
反过来又需要\@Wrindex
;\@Wrindex
这是该过程的核心,因为它将条目写入.idx
文件中。所以我这样修补它,立即地写入计数器的当前值。这里\protected@iwrite
与 相同\protected@write
,但执行\immediate\write
而不是通常的延迟\write
,因为我们不需要仅在输出例程期间才知道的页码。
(3)真正的\Index
命令是对以下有用函数的包装制作索引,通常用于表示“看……”。
(4)我们通过制作索引选项-s raphink
,其中raphink.ist
是仅包含样式的文件
delim_0 ""
不会在条目后添加逗号。
\Index{Veni Sancte Spiritus}
现在,诸如“1 月 1 日”部分中的命令将会写入
\indexentry{Veni Sancte Spiritus|transform}{1}
在.idx
文件中(假设计数器的当前值为 1)。如果我们\Index{Veni Sancte Spiritus}
在五旬节也写上,我们将得到如下条目
\indexentry{Veni Sancte Spiritus|transform}{150}
处理makeindex -s raphink
(由伊玛克) 将在文件中提供以下内容.ind
:
\item Veni Sancte Spiritus \transform{1, 150}
宏读取逗号分隔的列表,然后使用包含正确章节标题的\transform
命令\csname cursec1\endcsname
和进行拆分。\csname cursec150\endcsname
实施
以下是示例文档中的宏。
\begin{filecontents*}{raphink.ist}
delim_0 ""
\end{filecontents*}
\documentclass[a4paper]{report}
\usepackage{etoolbox}
\newcounter{indexcnt}
\newcommand\Section[1]{%
\stepcounter{indexcnt}%
\expandafter\gdef\csname cursec\theindexcnt\endcsname{#1}%
\section{#1}}
\usepackage{imakeidx}
\makeindex[options=-s raphink]
\makeatletter
\let\@Index\@index
\patchcmd{\@Index}{\@wrindex}{\@Wrindex}{}{}
\let\@Wrindex\@wrindex
\patchcmd{\@Wrindex}{\thepage}{\theindexcnt}{}{}
\let\xIndex\index
\patchcmd{\xIndex}{\@index}{\@Index}{}{}
\patchcmd{\xIndex}{\@index}{\@Index}{}{}
\let\protected@iwrite\protected@write
\patchcmd{\protected@iwrite}{\write}{\immediate\write}{}{}
\patchcmd{\@Wrindex}{\protected@write}{\protected@iwrite}{}{}
\makeatother
\newcommand{\Index}[1]{\xIndex{#1|transform}}
\newcommand{\transform}[1]{\forcsvlist\decodesec{#1}}
\newcommand{\decodesec}[1]{, \csname cursec#1\endcsname}
\begin{document}
\chapter{Christmas}
\Section{January 1st}
...
Veni Sancte Spiritus\Index{Veni Sancte Spiritus}
...
\chapter{Easter}
\Section{Pentecost}
...
Veni Sancte Spiritus\Index{Veni Sancte Spiritus}
...
\printindex
\end{document}
答案2
这是我对 @egreg 的答案的最终实现。\thepage
尽管他的想法是使用计数器,但它还是使用了。这样做的原因是我想在索引中生成超链接,如果我不知道要链接到的页面,这是不可能的,而且我不想玩数百个动态标签。总而言之,这很有效,我对此很满意:
\newcommand{\getpagedate}[1]{%
\csname pagedate#1\endcsname
}
\usepackage{etoolbox}
\newcommand{\transform}[1]{
\def\secondparam{0}%
\forcsvlist\decodesec{#1}}
\newcommand{\decodesec}[1]{%
\ifthenelse{\secondparam=1}{, }{}%
\hyperlink{page.#1}{\mbox{\scshape\getpagedate{#1}}}%
\def\secondparam{1}}
\renewcommand*{\bvidxpgformat}{transform}
\newcommand{\dvday}[1]{\newpage\section{#1}%
\expandafter\xdef\csname pagedate\thepage\endcsname{\noexpand\makedate{\thesection}~\chaphead}%
}
结果图如下: