我尝试生成一个索引,其中的条目不是按普通字母 A、B、C 等分组,而是按圣经的书籍(例如 Num、Dtn、Ps 等)分组。所以我的问题是如何根据圣经定义自定义字母组列表据我理解xindy
手册,我要做的就是define-letter-groups
在自定义样式文件中添加一些新的字母组,但我的尝试失败了。
这是我的 M(not)WE:
% !TeX program = xelatex
\begin{filecontents}{index-style.xdy}
(require "tex/inputenc/utf8.xdy")
(require "texindy.xdy")
(require "page-ranges.xdy")
(require "book-order.xdy")
(markup-locclass-list :open ": ")
(define-letter-groups ("Num" "Dtn" "Ps"))
\end{filecontents}
\documentclass[a6paper,DIV=20]{scrartcl}
\usepackage[xindy]{imakeidx}
\makeindex[options = -M index-style -C utf8]
\begin{document}
Test
\index{Ps 1}
\index{Ps 10}
\index{Ps 2}
\index{Ps 1}
\index{Ps 3}
\index{Ps 56}
\index{Ps 5}
\index{Ps 34,1--2}
\index{Ps 34,7}
\index{Ps 34,1}
\index{Ps 34|full}
\index{Ps 34}
\index{Dtn 3,7.9}
\index{Dtn 3,5}
\index{Dtn 3,8}
\index{Num 122,3}
\index{Num 121}
\printindex
\end{document}
不幸的是,手册xindy
并没有真正详细说明字母组,据我所知,我的样式文件中没有做错任何事,但我担心我遗漏了一些重要的东西。
我在 TeX.SX 上发现了什么:
- xindy:如何向字母表添加新字母和字母组?有两个答案,但只针对巴利语添加组的特殊问题。我无法理解第一个答案并将其转移到我的问题中。第二个答案稍微简单一点,但即使我按照步骤一步一步尝试重现结果,它也无法工作。也就是说,2011 年的代码似乎不起作用。
- 答案是Xindy 无法正确排序关键词建议我先定义一种新语言。这是真的吗?那为什么手册中没有提到这一点
xindy
……? - 带有 xindy 的圣经经文索引有答案但没有真正的解决方案……
这回答在xindy:删除索引条目的规则也使用自定义字母组,但另外还有一个奇怪的(什么样的特殊序列
~b
?)合并规则。然而,它似乎是一个解决方法如果我使用非普通字母的前缀:(define-letter-groups ("Num" "Dtn" "Ps")) (define-letter-group "Dtn" :prefixes ("#")) (merge-rule "^Dtn" "#") (define-letter-group "Num" :prefixes ("@")) (merge-rule "^Num" "@") (define-letter-group "Ps" :prefixes ("<")) (merge-rule "^Ps" "<")
但这不可能是预期的解决方案……
- 这回答在使用 xindy 词汇表对希腊字母进行奇怪的排序使用新的字母组来表示希腊字母,在这种情况下不使用合并规则。
最后两个问题让我想到,我的字母组的问题在于它们只由普通字母组成,并且被忽略,因为已经有了普通字母的组。然而手册上xindy
说
使用具有不同字母方案的语言时会出现更多问题。匈牙利语就是一个例子。在匈牙利语索引中,以字母 Cs、Ly、Ny 等开头的单词会打印在单独的块中。例如,以 Ly 开头的单词出现在以 L 开头的单词后面。xindy 也允许定义这种字母组。将以下几行添加到样式文件中。
(define-letter-group "ly" :after "l" :before "m") (define-letter-group "ny" :after "n" :before "o") (markup-letter-group :open-head "~n {\bf " :close-head "}" :capitalize)
这显然是一个只有字母的例子……
其他解决方法只使用合并规则并将每本书映射到字母表中的字母,然后添加一些 TeX 代码来转换\lettergroup{A}
为输出數量。
编辑:请仅将圣经书籍视为一使用新字母组的示例。我并不是在寻找排版/索引圣经书籍的进一步解决方法,而是关于如何定义字母组的一般解决方案xindy
。
答案1
最简单的解决方案是使用克林贡人:改变行
\makeindex[options = -M index-style -C utf8]
在你的 TeX 文件中
\makeindex[options = -M index-style -C utf8 -L klingon]
这将生成一个 PDF 文件,其索引页排版如下:
我相信这就是你想要的。
长答案:
对我来说,这是软件测试方面的一个很好的教训:我必须将程序视为xindy
黑盒,因为它的文档很糟糕,甚至具有误导性。事实上,在我花了很多时间试图弄清楚这一点的过程中,我朝着解决方案迈出的最大一步就是我决定完全不再相信文档的那一刻。
以下并非我得出该解决方案/理解的确切过程,而是一个略带“虚构”的描述,可能有。
回顾一下问题:将问题的 LaTeX 源保存为question.tex
,更改filecontents
为filecontents*
(这样它就不会将%%
注释写入文件),然后运行xelatex -shell-escape question.tex
(注意:shell-escape
通常是危险的;在没有绝对确定文件可以安全运行的情况下,不应使用该选项),我们得到一个排版的 PDF,其索引页如下所示:
所以问题是它似乎完全忽略了(define-letter-groups ...
索引样式。
如果你查看日志文件(question.log
),它会提到调用的程序:
runsystem(texindy -M index-style -C utf8 question.idx)...executed.
texindy -M index-style -C utf8 question.idx
您可以自己验证一下这个命令( )的作用是question.idx
:
\indexentry{Ps 1}{1}
\indexentry{Ps 10}{1}
\indexentry{Ps 2}{1}
\indexentry{Ps 1}{1}
\indexentry{Ps 3}{1}
\indexentry{Ps 56}{1}
\indexentry{Ps 5}{1}
\indexentry{Ps 34,1--2}{1}
\indexentry{Ps 34,7}{1}
\indexentry{Ps 34,1}{1}
\indexentry{Ps 34|full}{1}
\indexentry{Ps 34}{1}
\indexentry{Dtn 3,7.9}{1}
\indexentry{Dtn 3,5}{1}
\indexentry{Dtn 3,8}{1}
\indexentry{Num 122,3}{1}
\indexentry{Num 121}{1}
进入question.ind
:
\begin{theindex}
\providecommand*\lettergroupDefault[1]{}
\providecommand*\lettergroup[1]{%
\par\textbf{#1}\par
\nopagebreak
}
\lettergroup{D}
\item Dtn 3,5: 1
\item Dtn 3,7.9: 1
\item Dtn 3,8: 1
\indexspace
\lettergroup{N}
\item Num 121: 1
\item Num 122,3: 1
\indexspace
\lettergroup{P}
\item Ps 1: 1
\item Ps 2: 1
\item Ps 3: 1
\item Ps 5: 1
\item Ps 10: 1
\item Ps 34: 1
\item Ps 34,1: 1
\item Ps 34,1--2: 1
\item Ps 34,7: 1
\item Ps 56: 1
\end{theindex}
错误已经在这里显现出来了。所以现在我们可以忘记 TeX 的东西,专注于使用(或其他)命令question.ind
来获得所需的结果。question.idx
texindy
该texindy
命令有一些调试选项。例如,添加--debug script
显示本质上是texindy
调用。我们可以直接运行它,并看到它产生相同的输出(“坏的” )。xindy
xindy -d script -L general -C utf8 -M tex/inputenc/utf8 -M texindy -M page-ranges -M word-order -M index-style.xdy -I latex question.idx
question.ind
自动包含的模块列表texindy
还表明我们的某些行index-style.xdy
是多余的:我们可以将其归结为
(markup-locclass-list :open ": ")
(define-letter-groups ("Num" "Dtn" "Ps"))
并保持输出不变。我们可以进一步将命令简化xindy
为xindy -M texindy -M index-style question.idx
。现在我们可以xindy
直接运行,而不是texindy
。
要继续探索调试选项,第一件事是将xindy
日志记录到文件中,而不是将其丢弃(到/dev/null
)。这是通过完成的-t question.ilg
。此日志文件的输出如下
Forming letter-groups:
Letter-group: "?? 0000001" -> "P"
Letter-group: "?? 0000010" -> "P"
等等,它们显然与输入的行一一对应(question.idx
)。 (??
它在我的终端上显示,但我可以在编辑器中打开它以查看实际的字节:例如less
显示第二行,其中Letter-group: "<C8><D0> 0000010" -> "P"
这两个字符突出显示。)
因此,由于某种原因,它将输入条目转换\indexentry{Ps 10}{1}
为"<C8><D0> 0000010"
,然后映射到字母组P
。
--debug level=1
(或更高)选项在xindy
日志中包含一些相关内容:类似以下行
Add sort rule to run 0: #<ordrule: '<E4>' => '<80>' :again NIL>
Add sort rule to run 0: #<ordrule: 'A' => '<80>' :again NIL>
...
Add sort rule to run 0: #<ordrule: 'p' => '<C8>' :again NIL>
Add sort rule to run 0: #<ordrule: 'P' => '<C8>' :again NIL>
等等。但这仍然不能解释这些排序规则来自哪里。--debug script --debug keep_tmpfiles
不过,通过其余的调试选项,我们可以找出答案:首先,该命令使用一个名为的过滤器tex2xindy
将我们的文件转换.idx
为包含以下行的文件:
(indexentry :tkey (("Ps 1")) :locref "1")
(indexentry :tkey (("Ps 10")) :locref "1")
(完全使用 Lisp 语法)。我们很快就会知道,这个文件称为“rawindex”。然后,xindy 的“核心”使用以下命令运行:
xindy.run -M /Library/TeX/texbin/xindy.mem -E iso-8859-1 -x (progn
(searchpath ".:/usr/local/texlive/2015/texmf-dist/xindy/modules:/usr/local/texlive/2015/texmf-dist/xindy/modules/base")
(xindy:startup
:idxstyle "<tmp file 1>"
:rawindex "<above tmp file>"
:output "./question.ind"
:logfile "question.ilg"
)
(exit))
我们可以直接运行此命令,并看到它(仍然)生成相同的.ind
文件。我们越来越接近了:查看上面的 tmp 文件(属性:idxstyle
),它看起来像:
(require "lang/general/latin9-lang.xdy")
(require "texindy.xdy")
(require "index-style.xdy")
最后两行(共三行)由我们的命令行手动指定xindy -M texindy -M index-style
;第一行由 xindy 自动插入。(latin9
这里无关紧要;如果我们使用,-C utf8
我们会得到lang/general/utf8-lang.xdy
这里,其中的问题是一样的。)查看该文件(texmf-dist/xindy/modules/lang/general/latin9-lang.xdy
),它以
(require "lang/general/latin9.xdy")
和那文件以如下行开头:
(define-letter-group "A" :prefixes ("<80>"))
(define-letter-group "B" :after "A" :prefixes ("<84>"))
(define-letter-group "C" :after "B" :prefixes ("<86>"))
(define-letter-group "D" :after "C" :prefixes ("<8D>"))
这暗示了发生了什么:到define-letter-group
涉及时,字符已经转换为字节(回想一下我们之前看到的"<80>"
日志行)。因此,这些命令不是针对索引文件中的原始输入进行操作,而是针对这些转换后的字节进行操作。Add sort rule to run 0: #<ordrule: 'A' => '<80>' :again NIL>
define-letter-group
此时,我们可以使用与此文件相同的字节替换来获得解决方案 1:使用以下 Python 脚本创建文件index-style.xdy
,其内容与原始文件稍有修改:
s = '''
(markup-locclass-list :open ": ")
(define-letter-group "Num" :prefixes ("\xbc\xe0\xbb"))
(define-letter-group "Dtn" :prefixes ("\x8d\xda\xbc") :after "Num")
(define-letter-group "Ps" :prefixes ("\xc8\xd0") :after "Dtn")
'''
open('index-style.xdy', 'w').write(s)
(这个 Python 脚本只是将文件内容作为字符串分配给变量s
并将该变量写入文件index-style.xdy
:您可以使用任何语言甚至是 shell 脚本;目标只是将二进制数据放入文件中。)
然后使用它index-style.xdy
来得到您想要的索引(如上面的屏幕截图所示)。
解释是,为什么这些转换发生时,在同一个文件中较低(现在我使用utf8.xdy
而不是latin9.xdy
):
(define-rule-set "xy-alphabetize"
:rules (("À" "<80>" :string)
("Ă" "<80>" :string)
("â" "<80>" :string)
...
("A" "<80>" :string)
...
))
该规则集用于utf8-lang.xdy
:
(use-rule-set :run 0
:rule-set ("xy-alphabetize" "xy-ignore-special"))
因为在第一次(第 0 次)运行中,所有字符都已经转换,这就是我们的(define-letter-groups ("Num" "Dtn" "Ps"))
不起作用的原因。文档中关于 的说法是正确的(define-letter-groups ...)
,因为该功能确实存在,并且 的核心xindy
支持它。但是,默认的“常规”配置(顺便说一下,在文件注释中记录为“西欧语言的常规排序顺序”)明确地做了一些妨碍的事情,而文档中没有提到如何处理这个问题。
如果他们提供的不是“通用”而是比“通用”更简单的“裸”“语言”(并且不会将字符转换为 ascii 范围之外的字节),那么使用(define-letter-groups
英文字母字符就可以了(就像给出-L bare
或其他一样简单)。
为了确认情况确实如此,我们可以采取另一种方法(解决方案 2), 给出一个明确的文件 (没有第一行),而不是 的临时文件idxstyle
。在这个文件中,我们删除第一行,只保留和 的(require "lang/general/latin9-lang.xdy")
要求。如果我们这样做,例如,我将这两行放入一个名为的文件中,并将命令更改为texindy
index-style.xdy
forced-idxstyle
xindy.run
/Library/TeX/texbin/xindy.run -M /Library/TeX/texbin/xindy.mem -E iso-8859-1 -x '(progn (searchpath ".:/usr/local/texlive/2015/texmf-dist/xindy/modules:/usr/local/texlive/2015/texmf-dist/xindy/modules/base") (xindy:startup :idxstyle "./forced-idxstyle" :rawindex "<same tmp file as before>" :output "./question.ind" :logfile "question.ilg") (exit))'
它起作用了:我们的纯index-style.xdy
文件只有两行
(markup-locclass-list :open ": ")
(define-letter-groups ("Num" "Dtn" "Ps"))
现在开始提供question.ind
我们想要的精确文件(我们可以运行xelatex
并在索引中获得所需的排版输出)。
这证实了其define-letter-groups
工作方式与文档所述一致,并且如果不是因为所有 xindy 的默认语言所做的所有“有用的”转换,将重音字母与非重音字母视为相同,最终用户(我们)仍然可以使用它。
其实并不是全部:在附带的语言中,xindy
有一些语言不支持拉丁字母字符,尤其是不能将“A”(例如)转换为其他任何字符:
白俄罗斯语 保加利亚语 格鲁吉亚语 希腊语 希伯来语 克林贡语 韩语 马其顿语 俄语 塞尔维亚语 乌克兰语
其中,如果你真的想要一种在使用英语时永远不会妨碍的语言,那么“韩语”是最有希望的,因为其他语言(甚至是克林贡语,它甚至不在 Unicode 中,并使用私有区域字符!)确实会转换一些“特殊”字符,如连字符和分号。因此,这给出了解决方案 3我把它放在这个答案的顶部:保留你原来的索引样式,保留你原来的 TeX 文件,只需附加-L korean
到索引命令中,你就会得到你想要的索引。(其他语言,如克林贡语等也可以使用。)
答案2
我在工作中解决了这个问题,没有使用 xindy。我的替代方法是使用排序键。因此:\index{19@Psalms!0901 @9:1}
.19
是希伯来圣经中诗篇的顺序,因此符号前的这个数字@
将按正确顺序对书籍进行排序。感叹号 ( !
) 使书籍本身(诗篇)和诗句将作为其下的子项目进行索引。如果您希望在每个引用之前都显示书名,则可以将其删除。0901
是 9:1 的排序代码,其中零可防止从 10 开始的章节(例如:11:1)首先列出。空格可防止诗句范围出现在单个诗句之前,因此0901_
将排在 之前0901-07
。(这是 Barbara Beeton 的天才见解,来自另一篇帖子)。
如果你有\index{05@Deuteronomy!1212 @12:12} \index{02@Exodus!0101-12@1:1-12} \index{19@Psalms!0901 @9:1}
这个,现在应该会得到正确的圣经顺序。所以:
出埃及记
1:1-12
申命记
12:12
诗篇
9:1
我自己更喜欢这个解决方案。你可能还想看看Bibleref 包也是。我没有用过,但我相信它可以与索引一起使用。