summaryrefslogtreecommitdiff
path: root/indexing/zhmakeindex/doc/zhmakeindex.tex
blob: 675ccd9ff8e3240c120f2c8cb986de9f3839b399 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
\documentclass[UTF8]{ctexart}

\usepackage{etoolbox}

\setmainfont[Ligatures=TeX]{CMU Serif}
\setsansfont[Ligatures=TeX]{CMU Sans Serif}
\setmonofont[Mapping=]{CMU Typewriter Text}
\setCJKmainfont[BoldFont=FandolSong Bold,ItalicFont=FandolKai]{FandolSong}
\newfontfamily\libertine{Linux Libertine O}

\usepackage{pifont}
\newcommand\gooditem{\item[\ding{51}]}
\newcommand\baditem{\item[\ding{55}]}

\usepackage[a4paper,centering,margin=1.2in]{geometry}

\ctexset{section/format=\bfseries\Large}

\usepackage[numbers,square,sort&compress]{natbib}
\renewcommand\bibname{参考文档}
\bibliographystyle{plainnat}

\usepackage{tocbibind}

\usepackage{ragged2e}

\usepackage{booktabs}
\usepackage{longtable}
\usepackage{tabu}

\usepackage{caption}
\captionsetup[table]{font=small,position=top,skip=1ex}

\usepackage{xcolor}

\usepackage{makeidx}
\makeindex

% 索引项示例
\newenvironment{idxexample}
  {\newcommand{\sindex}{%
     \end{tabular}%
     &
     \begin{tabular}[t]{@{}l@{}}}
   \newcommand{\sitem}{\hspace*{20pt}}
   \newcommand{\ssitem}{\hspace*{30pt}}
   \begin{quote}
   \begin{tabular}{@{}l @{\quad{\color{gray}\vrule width .25em}\quad} l @{}}
     \begin{tabular}[t]{@{}l@{}}}
  {  \end{tabular}
   \end{tabular}
   \end{quote}}

\usepackage{fancyvrb}
\fvset{formatcom=\xeCJKVerbAddon}
\usepackage{shortvrb}
\AtBeginDocument{
  \MakeShortVerb\|
  \MakeShortVerb\"
}

\makeatletter
\appto\@sanitize{%
  \@makeother\|%
  \@makeother\"}
\def\useangles{%
  \@makeother\{%
  \@makeother\}%
  \catcode`\<=1%
  \catcode`\>=2}
\def\restoreangles{%
  \@makeother\<%
  \@makeother\>%
  \catcode`\{=1%
  \catcode`\}=2}
\let\org@wrindex\@wrindex
\let\rawindex\index
\patchcmd\rawindex{\@wrindex}{\org@wrindex}
  {}
  {\GenericWarning
    {\space\space\space\space}
    {hyperref index patch failed.}}
\makeatother

\usepackage{hyperref}
\hypersetup{bookmarksnumbered,pdfstartview=FitH}
\def\tableautorefname{表}

\usepackage{xspace}

\newcommand*\pkg[1]{\textsf{#1}\index{#1@\textsf{#1}}}
\newcommand*\zhm{\pkg{zhmakeindex}\xspace}
\newrobustcmd*\meta[1]{$\langle\textnormal{\itshape#1}\rangle$}
\newcommand*\optional[1]{\textnormal{[}#1\textnormal{]}}
\def\defchar#1{\begingroup\lccode`~=`#1\lowercase{\endgroup\def~}}
\newenvironment{syntax}{%
  \quote\ttfamily
  \catcode`<\active  \defchar<##1>{\meta{##1}}
  \catcode`[\active  \defchar[##1]{\optional{##1}}
}{\endquote}
\newcommand*\optindex[1]{\index{选项!\texttt{#1}}}
\newcommand*\optitem[1][]{\optindex{#1}\item[#1]}
\newrobustcmd*\textkw[1]{\texttt{\scantokens{\catcode`\_=12 #1\endinput}}}
\newcommand*\kwindex[1]{\index{#1@\textkw{#1}}}
\newcommand*\kw[1]{\kwindex{#1}\textkw{#1}}
\newcommand*\sort[1]{%
  \index{选项!\texttt{-z}!#1@\textkw{#1}}%
  \textkw{#1}}
\newcommand\email{\nolinkurl}

\InputIfFileExists{zhm-version}{}{%
  \def\zhmVersion{???}%
  \def\zhmRevision{???}}

\title{\zhm\thanks{版本 \zhmVersion-\zhmRevision} 中文索引处理程序}
\author{刘海洋}
\date{2018 年 4 月 11 日}

\begin{document}

\maketitle

\section{命令行}

\index{命令行}
\begin{syntax}
\halign{#&#\hfil\cr
zhmakeindex &[-c] [-i] [-o~<ind>] [-q] [-r] [-s~<sty>] [-t~<log>]\cr
            &[-enc~<enc>] [-senc~<senc>] [-strict] [-z~<sort>]\cr
            &[<idx0> <idx1> <idx2> ...]\cr
}
\end{syntax}

\section{简介}

\zhm 是一个通用的中文多级索引处理程序,它从一个或多个输入文件读入索引项,将其
内容按指定的方式分组、排序,然后按格式将整理好的索引输出到文件。索引项可以有 3
个级别(0, 1, 2)的嵌套。\zhm 主要用于 \LaTeX{} 索引的处理,其功能和用法与
\pkg{makeindex}\cite{Chen1991} 相似,并支持中文的分组与排序。

\index{.idx@\verb+.idx+}
\index{.ind@\verb+.ind+}
输入与输出文件的格式由一个格式文件确定。默认的输入/输出是 ".idx"/".ind" 格式
的,即 \LaTeX{} 格式的索引文件。

如果没有显式指定,第一个输入文件(\meta{idx0})的主文件名将用于确定输出和日志
文件的主文件名。对每个输入文件名 \meta{idx0}, \meta{idx1}, \ldots, \zhm 会首先
查找这个名字的文件;如果找不到且文件名没有后缀,则加上 ".idx" 后缀查找此文件;
如果还找不到文件,\zhm 则会中止。

\optindex{-s}
\index{.mst@\verb+.mst+}
如果只有一个输入文件,并且没有显式用 "-s" 选项指定格式文件,\zhm 会使用后缀为
".mst" 的默认格式文件(如果存在的话)。

关于如何使用 \pkg{makeindex} 在 \LaTeX{} 文档中处理索引,可以参考陈丕宏较早的
文档 \cite{Chen:1988:IPP},或 Lamport 的文档 \cite{Lamport1987}。\zhm 的在
\LaTeX 中的使用方法与 \pkg{makeindex} 基本一致。

\section{选项说明}

\index{选项|(}

\subsection{与 \pkg{makeindex} 相同的选项}
\label{subsec:oldoption}

\begin{description}
  \optitem[-c] 压缩索引项排序项前后的空格。默认情况下,排序项中的空格会被保留。
  \optitem[-i] 从标准输入流("stdin")读入索引项。如果使用了该选项,并且没有使用
    "-o" 选项,则排序后的索引将输出到标准输出流("stdout")。
  \optitem[-o~\meta{ind}] 设置输出索引文件为 \meta{ind}。如果没有指定该选项,默认
    的输出文件名是第一个输入文件 \meta{idx0} 的主文件名加上 ".ind" 的扩展名。
    \index{.ind@\verb+.ind+}
  \optitem[-q] 静默模式,不向标准错误流("stderr")显示信息。默认情况下处理过程与
    错误信息会同时在 "stderr" 与日志文件中输出。
  \optitem[-r] 禁止隐式页码区间构造,要求页码区间必须使用显式区间符号生成。见
    第~\ref{sec:idxsyntax} 节的说明。默认情况下,三个或三个以上连续的页码会自
    动合并为一个页码区间(如 1--5)。
  \optitem[-s~\meta{sty}] 设置 \meta{sty} 为格式文件。没有默认值。如果没有后
    缀,会加上 ".ist" 后缀。\zhm 会首先在当前目录查找格式文件,如果找不到则调
    用 \TeX{} 发行版的 \pkg{kpathsea} 库在 TEXMF 树中查找。
    \index{.ist@\verb+.ist+}
  \optitem[-t~\meta{log}] 设置 \meta{log} 为日志文件。默认情况下,会使用第一个输
    入文件 \meta{idx0} 的主文件名加上 ".ilg" 后缀作为日志文件。
    \index{.ilg@\verb+.ilg+}
\end{description}

\subsection{\zhm 独有的选项}
\label{subsec:newoption}

\begin{description}
  \optitem[-enc~\meta{enc}] 设置输入输出文件的编码为 \meta{enc}。可选的编码包括
    "UTF-8", "UTF-16", "GB18030", "GBK" 和 "Big5",不区分大小写。默认使用
    UTF-8 编码。
    \index{编码!UTF-8}
    \index{编码!UTF-16}
    \index{编码!GB18030}
    \index{编码!GBK}
    \index{编码!Big5}
  \optitem[-senc~\meta{senc}] 设置读入格式文件的编码为 \meta{senc}。可选的编码与
    "-enc" 选项相同。默认使用 UTF-8 编码。
  \optitem[-strict] 严格区分不同嵌入命令的页码。默认情况下,在页码区间处理时,会
    将如果页码左区间的嵌入命令与右区间不匹配,会以左区间为准(部分 \LaTeX{} 文
    档会生成右区间命令缺失的索引项);而如果使用 "-strict" 选项,则要求左右区
    间的命令类型必须严格匹配。
  \index{分组}\index{排序}
  \optitem[-z~\meta{sort}] 设置中文分组与排序方式为 \meta{sort}。可选的中文分
    组排序方式包括 \sort{pinyin}/\sort{reading}, \sort{bihua}/\sort{stroke},
    \sort{bushou}/\sort{radical}。默认值为 \sort{pinyin},即中文按拼音分组排
    序。有关分组与排序的详细说明见第~\ref{sec:sort} 节。
\end{description}

\subsection{未实现的选项}
\label{subsec:unsupportedoption}

\optindex{-g}
\optindex{-l}
\optindex{-p}
\optindex{-L}
\optindex{-T}
\zhm 没有实现 \pkg{makeindex} 的 "-g", "-l", "-p", "-L", "-T" 选项。其中,选项
"-p" 依赖对 \TeX{} 编译的日志文件的解析,可能在未来版本实现;另外几个语言相关
的排序选项("-g" 德文,"-T" 泰文,"-L" 做系统 locale 选择,"-l" 有关西文单词排
序)对中文索引意义较小,不在 \zhm 中实现。

\index{选项|)}

\section{索引项输入语法}
\label{sec:idxsyntax}

\zhm 输入索引项的语法与 \pkg{makeindex} 相同。下面以默认的格式输入设置(即在
\LaTeX{} 中使用)为例对索引项输入语法进行说明。

索引项文件是一个由多条索引项组成的文本文件,每行一条索引项,允许有空行,但索引
项不得跨行。

一个简单的索引项及其输出如
\begin{idxexample}
"\indexentry{简介}{15}" \\
\sindex
简介, 15
\end{idxexample}
其语法为:
\begin{syntax}
"\indexentry{"<条目>"}{"<页码>"}"
\end{syntax}

在 \LaTeX{} 中,"\indexentry" 项是在编译过程中自动生成的,实际生成上面例子的
\LaTeX{} 代码并不包括页码问题,只是在文档 15 页的源文件处输入 "\index{简介}"
即可得到这样的效果。关于 \pkg{makeindex} 在 \LaTeX{} 中的使用可以参考文档
\cite{Lamport1987,Chen:1988:IPP}。

\useangles
\index<"{@\verb+"{+>
\index<"}@\verb+"}+>
\restoreangles
"\indexentry" 是在索引输入文件中表示索引项的关键字。可以使用 \kw{keyword} 输入
格式进行修改(\autoref{tab:oldinputstyle})。左右花括号是界定 \meta{条目} 与
\meta{页码} 的标记,可以使用 \kw{arg_open}, \kw{arg_close} 输入格式修改
(\autoref{tab:oldinputstyle})。

\index{页码}
\meta{页码} 是一个数字,可以使用阿拉伯数字、大小写罗马数字、大小写拉丁字母共 5
种格式。

\index{-@\verb+-+}
此外,与 \pkg{makeindex} 类似 \cite{Rodgers1991},\zhm 还支持多级页码。可以使
用 "-" 划分不同级别的复合页码。页码分隔符可由 \kw{page_compositor} 输入格式修
改,见 \autoref{tab:oldinputstyle}。例如:
\begin{idxexample}
"\indexentry{方程}{5-ii-2}" \\
"\indexentry{方程}{5-ii-1}" \\
"\indexentry{方程}{3-v-9}"
\sindex
方程, 3-v-9, 5-ii-1, 5-ii-2
\end{idxexample}

\meta{条目} 是 \zhm 需要处理的正文内容。最简单的条目就是一个普通的词条串,但也
可以有复杂的格式。

\index{"@@\verb+"@+}
如果对条目排序使用的串与用来输出条目的 \LaTeX{} 代码不一样,则可以把这两部分用
符号 "@" 分开,前面是排序的键,后面是输出的值。例如:
\begin{idxexample}
"\indexentry{Gamma 射线@$\Gamma$ 射线}{2}" \\
"\indexentry{粗体@\textbf{粗体}}{3}"
\sindex
\textbf{粗体}, 3 \\
$\Gamma$ 射线, 2
\end{idxexample}
分隔符 "@" 可通过修改格式文件的 \kw{actual} 项配置
(\autoref{tab:oldinputstyle})。

\index{"!@\verb+"!+}
索引项的条目可以分成至多三级,不同级别之间用符号 "!" 分开。例如
\begin{idxexample}
"\indexentry{方程!解}{1}" \\
"\indexentry{方程!代数方程!线性方程}{2}" \\
"\indexentry{方程!代数方程!二次方程}{3}"
\sindex
方程 \\
\sitem 代数方程 \\
\ssitem 二次方程, 3 \\
\ssitem 线性方程, 2 \\
\sitem 解, 1
\end{idxexample}
每一级别内部都可以分别指定排序的键与输出值,例如:
\begin{idxexample}
"\indexentry{射线!Gamma 射线@$\Gamma$ 射线}{8}" \\
"\indexentry{射线!X 射线}{9}"
\sindex
射线 \\
\sitem $\Gamma$ 射线, 8 \\
\sitem X 射线, 9
\end{idxexample}
即分隔符 "!" 的优先级低于 "@"。分隔符 "!" 可通过修改格式文件的 \kw{level} 项配
置(\autoref{tab:oldinputstyle})。

\rawindex{"|@\verb+"|+|hyperpage}
索引项条目中也可以在最后指定页码的输出格式,用分隔符 "|" 与前面分开(用
\autoref{tab:oldinputstyle} 中的 \kw{encap} 项配置)。页码的输出格式由一个带单
个页码参数的 \TeX{} 命令决定,在输入索引项时这一特殊命令的反斜线 "\" 和左右花
括号被忽略,输出时会自动加上(用\autoref{tab:oldoutputstyle} 中的
\kw{encap_prefix}, \kw{encap_infix}, \kw{encap_suffix} 项配置)。例如:
\begin{idxexample}
"\indexentry{字体|emph}{2}"
\sindex
字体, \emph{2}
\end{idxexample}
它输出的代码实际上是
\begin{verbatim}
字体, \emph{2}
\end{verbatim}

\rawindex{"|@\verb+"|+|hyperpage}
\index{"(@\verb+"(+}
\index{")@\verb+")+}
除了指定页码输出格式的特殊命令,还可以指定页码范围,在分隔符 "|" 后、特殊命令
名前(如果有的话),使用开定界符 "(" 和闭定界符 ")",分别表示页码范围的起始和
结束。例如:
\begin{idxexample}
"\indexentry{方程|(}{5}" \\
"\indexentry{方程|)}{9}" \\
"\indexentry{函数!二次函数|(emph}{11}" \\
"\indexentry{函数!二次函数|)emph}{15}"
\sindex
方程, 5--9 \\
函数 \\
\sitem 二次函数, \emph{11--15}
\end{idxexample}
页码范围的开闭定界符可由\autoref{tab:oldoutputstyle} 中的 \kw{range_open} 与
\kw{range_close} 项配置。

\index{""@\verb+""+}
\index{转义符}
由于在索引条目中,"{", "}", "(", ")", "!", "@", "|" 等多种符号都有特殊意义,因
此引入引号 |"| 作为索引条目的转义符,引号及紧跟引号的字符都作为普通的单个后一
字符看待,不作为索引条目的特殊语法符号。例如:
\begin{idxexample}
|\indexentry{Aha"!}{1}| \\
\verb/\indexentry{绝对值 $"|x"|$}{2}/
\sindex
Aha!, 1 \\
绝对值 $\vert x\vert$, 2
\end{idxexample}
引号字符 |"| 可以由\autoref{tab:oldinputstyle} 中的 \kw{quote} 项配置。

\index{"\@\verb+"\+}
\index{转义符}
使用转义符有一个例外,就是在反斜线后的引号 |\"| 被解释为普通 \TeX{} 命令
|\"|,这是因为 |\"| 经常被用于输入 G\"odel(|G\"odel|)这样的文字。注意这一例
外会影响 "\|" 等符号组合的输入。例如:
\begin{idxexample}
|\indexentry{G\"odel}{5}| \\
\verb/\indexentry{命令 \verb+"\"|+}{9}/
\sindex
G\"odel, 5 \\
命令 \verb+\|+, 9
\end{idxexample}
转义符 "\" 可以由\autoref{tab:oldinputstyle} 中的 \kw{escape} 项配置。

\section{格式文件}
\label{sec:ist}

\zhm 的格式文件与标准 \pkg{makeindex} 语法完全相同,内容也基本上相同,同时增加
了少量控制中文分组输出的格式。可以在 \zhm 中使用标准 \pkg{makeindex} 的格式文
件。

格式文件指明了 ".idx" 输入文件和最终输入文件的格式。该文件在当前工作目录或在
TEXMF 树中由 \pkg{kpathsea} 库查找。一个格式文件由一组 \meta{关键字} \meta{属
性} 的列表组成。\meta{关键字} 分为输出和输出两类。\meta{关键字} \meta{属性} 对
儿不要求以任何顺序出现。
\index{%@\verb+%+}
\index{注释}
以字符 \verb"%" 开头的行是注释。
\index{字符串}
\index{""@\verb+""+}
\index{`@\verb+`+}
\meta{属性} 可以有不同的类型,字符串是以任意双引号 |"| 或反引号 |`| 界定的串,
\index{字符}
\index{'@\verb+'+}
字符是以单引号 |'| 界定的单个字符,数字是一个整数。
\index{转义符}
\index{"\@\verb+"\+}
其中,双引号和单引号界定的串和字符,可以使用反斜线 "\" 符号作为转义符,以得到
特殊字符或引号本身;而反引号界定的串是 \zhm 特有的功能,它不使用转义符。格式文
件中没有指定的项目会使用其默认值。

\subsection{与 \pkg{makeindex} 兼容的格式}

\autoref{tab:oldinputstyle} 与\autoref{tab:oldoutputstyle} 的格式是在
\pkg{makeindex} 中有定义,同时也在 \zhm 中有支持的输入、输出格式。\zhm 的这部
分格式选项与 \pkg{makeindex} 意义相同,完全兼容。

\begin{longtabu*} to \linewidth{lll>{\RaggedRight}X}
\caption{与 \pkg{makeindex} 兼容的输入格式}\label{tab:oldinputstyle} \\
  \toprule
  关键字 & 类型 & 默认值 & 意义 \\
  \midrule
\endfirsthead
  \toprule
  关键字 & 类型 & 默认值 & 意义 \\
  \midrule
\endhead
  \bottomrule
\endfoot
  \kw{keyword}  & 字符串 & |"\\indexentry"| & 索引关键字 \\
  \kw{arg_open}  & 字符 & |'{'| & 参数的开定界符 \\
  \kw{arg_close}  & 字符 & |'}'| & 参数的闭定界符 \\
  \kw{range_open}  & 字符 & |'('| & 页码范围的开定界符 \\
  \kw{range_close}  & 字符 & |')'| & 页码范围的闭定界符 \\
  \kw{level}  & 字符 & |'!'| & 索引项层次分隔符 \\
  \kw{actual}  & 字符 & |'@'| & (区别于排序项的)实际输出项标志符 \\
  \kw{encap}  & 字符 & "'|'" & 页码和特殊命令指示符 \\
  \kw{quote}  & 字符 & |'"'| & 引号(转义符) \\
  \kw{escape}  & 字符 & |'\\'| & 转义 |quote| 的符号,在它后面的引号不作转义符
解释 \\
  \kw{page_compositor} &  字符串 & |"-"| & 复合页码分隔符 \\
\end{longtabu*}
\useangles\index<"{@\verb+"{+>\restoreangles
\useangles\index<"}@\verb+"}+>\restoreangles
\index{"(@\verb+"(+}
\index{")@\verb+")+}
\index{"!@\verb+"!+}
\index{"@@\verb+"@+}
\rawindex{"|@\verb+"|+|hyperpage}
\index{""@\verb+""+}
\index{"\@\verb+"\+}
\index{-@\verb+-+}

\begin{longtabu*} to \linewidth{lll>{\RaggedRight}X}
\caption{与 \pkg{makeindex} 兼容的输出格式}\label{tab:oldoutputstyle} \\
  \toprule
  关键字 & 类型 & 默认值 & 意义 \\
  \midrule
\endfirsthead
\toprule
关键字 & 类型 & 默认值 & 意义 \\
\midrule
\endhead
\bottomrule
\endfoot
\kw{preamble} &  字符串 & |"\\begin{theindex}\n"| & 索引导言代码\\
\kw{postamble} &  字符串 & |"\n\n\\end{theindex}\n"| & 索引末尾代码\\
\kw{group_skip} &  字符串 & |"\n\n  \\indexspace\n"| & 组间垂直间距\\
\kw{headings_flag} &  数字 & |0| & 控制显示分组名标题的旗标\\
\kw{heading_prefix} &  字符串 & |""| & 分组名标题的前缀\\
\kw{heading_suffix} &  字符串 & |""| & 分组名标题的后缀\\
\kw{symhead_positive} &  字符串 & |"Symbols"| & 当旗标 |headings_flag| 为正数时,符号的标题\\
\kw{symhead_negative} &  字符串 & |"symbols"| & 当旗标 |headings_flag| 为负数时,符号的标题\\
\kw{numhead_positive} &  字符串 & |"Numbers"| & 当旗标 |headings_flag| 为正数时,数字的标题\\
\kw{numhead_negative} &  字符串 & |"numbers"| & 当旗标 |headings_flag| 为负数时,数字的标题\\
\kw{item_0} &  字符串 & |"\n  \\item "| & 第 0 级条目间分隔\\
\kw{item_1} &  字符串 & |"\n    \\subitem "| & 第 1 级条目间分隔\\
\kw{item_2} &  字符串 & |"\n      \\subsubitem "| & 第 2 级条目间分隔\\
\kw{item_01} &  字符串 & |"\n    \\subitem "| & 第 0/1 级条目间分隔\\
\kw{item_x1} &  字符串 & |"\n    \\subitem "| & 第 0/1 级条目间分隔,其中第 0 级无页码\\
\kw{item_12} &  字符串 & |"\n      \\subsubitem "| & 第 1/2 级条目间分隔\\
\kw{item_x2} &  字符串 & |"\n      \\subsubitem "| & 第 1/2 级条目间分隔,其中第 1 级无页码\\
\kw{delim_0} &  字符串 & |", "| & 第 0 级条目与页码分隔\\
\kw{delim_1} &  字符串 & |", "| & 第 1 级条目与页码分隔\\
\kw{delim_2} &  字符串 & |", "| & 第 2 级条目与页码分隔\\
\kw{delim_n} &  字符串 & |", "| & 多个页码的分隔\\
\kw{delim_r} &  字符串 & |"--"| & 页码范围符号\\
\kw{delim_t} &  字符串 & |""| & 将插入到在页码列表末尾。如果页码列表为空,此项无
效果。 \\
\kw{encap_prefix} &  字符串 & |"\\"| & 页码特殊指令前缀\\
\kw{encap_infix} &  字符串 & |"{"| & 页码特殊指令中缀\\
\kw{encap_suffix} &  字符串 & |"}"| & 页码特殊指令后缀\\
\kw{page_precedence} &  字符串 & |"rnaRA"| & 不同类型页码的次序,默认值表示小写
  罗马、阿拉伯数字、小写字母、大写罗马、大写字母\\
\kw{suffix_2p} & 字符串 & |""| & 在 2 页的页码范围中代替 |delim_r| 和第二个页码\\
\kw{suffix_3p} & 字符串 & |""| & 在 3 页的页码范围中代替 |delim_r| 和后面的页码\\
\kw{suffix_mp} & 字符串 & |""| & 在更多页的页码范围中代替 |delim_r| 和后面的页码\\
\end{longtabu*}

\subsection{\zhm 特有的格式}

\zhm 定义了新的输入格式(\autoref{tab:newinputstyle}),以支持索引输入的行
注释。

\begin{table}[htbp]
\caption{\zhm 特有的输入格式}\label{tab:newinputstyle}
\begin{tabu*} to \linewidth{lll>{\RaggedRight}X}
\toprule
关键字 & 类型 & 默认值 & 意义 \\
\midrule
  \kw{comment}  & 字符 & \texttt{'\textpercent'} & 行注释的开始符 \\
\bottomrule
\end{tabu*}
\index{%@\verb+%+}
\index{注释}
\end{table}

\zhm 定义了一些新的输出格式(\autoref{tab:newoutputstyle}),用来控制按笔画数或
部首分组时,分组名的输出格式。

\begin{table}[htbp]
\caption{\zhm 特有的输出格式}\label{tab:newoutputstyle}
\begin{tabu*} to \linewidth{lll>{\RaggedRight}X}
\toprule
关键字 & 类型 & 默认值 & 意义 \\
\midrule
  \kw{stroke_prefix}             & 字符串 & |""| & 笔画数前缀 \\
  \kw{stroke_suffix}             & 字符串 & |" 画"| & 笔画数后缀 \\
  \kw{radical_prefix}            & 字符串 & |""| & 部首前缀 \\
  \kw{radical_suffix}            & 字符串 & |"部"| & 部首后缀 \\
  \kw{radical_simplified_flag}   & 数字 & 1 & 是否输出简化部首的标志 \\
  \kw{radical_simplified_prefix} & 字符串 & |"("| & 简化部首前缀 \\
  \kw{radical_simplified_suffix} & 字符串 & |")"| & 简化部首后缀 \\
\bottomrule
\end{tabu*}
\end{table}

\subsection{未实现的 \pkg{makeindex} 格式}

\autoref{tab:unsupportedoutputstyle} 中给出的是在标准的 \pkg{makeindex} 中定
义,但在 \zhm 中没有实现对应功能的格式。格式文件中如果出现这些格式,\zhm 将会
忽略它们。

\begin{table}[htbp]
\caption{未实现的输出格式}\label{tab:unsupportedoutputstyle}
\begin{tabu*} to \linewidth{lll>{\RaggedRight}X}
\toprule
关键字 & 类型 & 默认值 & 意义 \\
\midrule
\kw{setpage_prefix} &  字符串 & |"\n  \\setcounter{page}{"| & 页码设置前缀\\
\kw{setpage_suffix} &  字符串 & |"}\n"| & 页码设置后缀\\
\kw{line_max} &  数字 & |72| & 最大行长度,超出长度会自动折行\\
\kw{indent_space} &  字符串 & |"\t\t"| & 自动折行的缩进\\
\kw{indent_length} &  数字 & |16| & |indent_space| 的长度\\
\bottomrule
\end{tabu*}
\end{table}

\subsection{格式文件示例}

合法的 \pkg{makeindex} 格式文件都是合法的 \zhm 格式文件。\LaTeXe{} 的
\pkg{doc} 包附带的 \path{gind.ist} 和 \path{gglo.ist} 就是两个实际的例子。此
外,\pkg{makeindex} 手册页 \cite{Rodgers1991} 也给出了几个有用的例子。

下面是本文档使用的格式文件,注意其中反引号格式的串是 \zhm 特有的:
\VerbatimInput[numbers=left]{zhmakeindex.mst}


\section{排序细节}
\label{sec:sort}

\subsection{索引项分组}

\optindex{-z}
\zhm 与 \pkg{makeindex} 类似,主要是按第一级索引项的排序项的首个字符分组的。对
最普通的场景,西文是按单词的首字母分组,中文则根据 "-z" 选项
(\ref{subsec:newoption}~节)的不同,选择对应的分组,数字和其他符号单独分组。

\zhm 的前 28 个分组是固定的,分别是符号、数字,以及 A--Z 的 26 个拉丁字母。按
笔画排序时,后面是按总笔画数分组的汉字,共 64 组;按部首笔画排序时,后面是按康
熙字典部首分组的汉字,共 214 组。详细情况见\autoref{tab:group}。

\begin{table}[htbp]
\caption{\zhm 支持的分组方式}\label{tab:group}
\begin{tabu} to \linewidth{lll@{\qquad}>{\RaggedRight}X}
\toprule
"-z" 选项 & 别名 & 前 28 个分组 & 后面的分组 \\
\midrule
\sort{pinyin} & \sort{reading} & 符号、数字、A, \ldots, Z & (无)\\
\sort{bihua} & \sort{stroke}   & 符号、数字、A, \ldots, Z & 1 画、2 画、……、64 画(共 64 组) \\
\sort{bushou} & \sort{radical} & 符号、数字、A, \ldots, Z & 一部、丨部、……、龠部(共 214 组) \\
\bottomrule
\end{tabu}
\end{table}

\zhm 主要是面向中文排版的索引处理,因此对于西文条目,只对没有重音等符号的拉丁
字母能进行正确的分组,对带重音符号的拉丁字母(如 é, ç)、非拉丁字母(如 Σ, Δ,
Ж, Я 等)等则会一律按符号分组。

\index{数字}
如果索引项的第一级排序项全部由数字组成,则该项会被分入数字分组;但如果条目的首
个字符是数字,后面还有其他字符,则条目会被计入符号分组。除了阿拉伯数字,\zhm
还将其他 Unicode 数字符号(如罗马数字“{\libertine Ⅳ}”、带圈数字“{\libertine ⑧}”)也当作数字处理,但汉字
数码“〇”被看作汉字处理。
\index{〇}

当索引项第一级排序项的首个字符不是拉丁字母或汉字,排序项本身也不是纯数字时,则
此索引项就会计入符号分组。

当输出格式变量 \kw{headings_flag} 非零时(参见\autoref{tab:oldoutputstyle}),
将输出分组名称。\kw{headings_flag} 是正数时,以大写字母显示分组名
称;\kw{headings_flag} 是负数时,以小写字母显示分组名称。

当使用汉字特有的分组时,分组名称可以使用格式文件定制(参见%
\autoref{tab:newoutputstyle})。按笔画分组时,分组名为
\begin{syntax}
\kwindex{stroke_prefix}
\kwindex{stroke_suffix}
  <stroke\_prefix><笔画数><stroke\_suffix>
\end{syntax}
按康熙字典部首分组时,如果变量 \kw{radical_simplified_flag} 非零(默认情况),
则分组名由原康熙字典部首与简化字部首组合而成:
\begin{syntax}
\kwindex{radical_prefix}
\kwindex{radical_suffix}
\kwindex{radical_simplified_prefix}
\kwindex{radical_simplified_suffix}
  <radical\_prefix><部首><radical\_suffix>\\
  \hspace*{2em}<radical\_simplified\_prefix><简化字部首><radical\_simplified\_suffix>
\end{syntax}
如果变量 \kw{radical_simplified_flag} 是零,则分组名没有简化字部首:
\begin{syntax}
\kwindex{radical_prefix}
\kwindex{radical_suffix}
  <radical\_prefix><部首><radical\_suffix>
\end{syntax}

\subsection{索引项排序}

大体上,\zhm 逐字符按字典序对索引项的排序项进行排序,汉字与其他 Unicode 字符一
样,按单个字符比较。排序时使用的字符串比较有一些特殊规则:
\begin{itemize}
  \item 如果字符串只包含阿拉伯数字,则首先按数字大小比较,数字相等时再按字典序
    比较。
  \item 以符号开头的字符串总是先于排在以数字开头的串(即使符号的 Unicode 码在
    数字之后),而这又先于纯数字的排序项和以字母开头的串。
  \item 在比较两个字符串时,\zhm 首先忽略字母大小写进行比较,如果此时结果相
    等,再按区分大小写进行比较,将大写字母排在小写字母之前。
\end{itemize}

\optindex{-l}
\pkg{makeindex} 有一个 "-l" 选项忽略条目中的空格,按所有非空白符比较所有条目
(\ref{subsec:unsupportedoption}~节)。\zhm 未提供此功能。

\optindex{-z}
按 "-z" 选项(\ref{subsec:newoption}~节)的不同,汉字可以使用不同的排序方式,
如\autoref{tab:sort} 所示。
\begin{table}[htbp]
\caption{\zhm 支持的中文排序方式}\label{tab:sort}
\begin{tabu} to \linewidth{ll>{\RaggedRight}X}
\toprule
"-z" 选项 & 别名 & 意义 \\
\midrule
\sort{pinyin} & \sort{reading} & 汉字按常用读音的拼音排序。 \\
\sort{bihua} & \sort{stroke} & 汉字按笔画数和笔顺排序。 \\
\sort{bushou} & \sort{radical} & 汉字按康熙字典部首和除部首笔画数排序。 \\
\bottomrule
\end{tabu}
\end{table}

使用读音排序时,没有读音数据的字符(包括生僻字)一律排在有读音的字符之前,汉字
按其最常用读音比较,读音相同汉字的按 Unicode 编码排序。使用笔画数和笔顺排序
时,笔画数小的排在前面,笔画数相同的,按横、竖、撇、点(捺)、折的顺序逐笔画比
较,仍然相同的按 Unicode 编码排序;生僻汉字没有笔顺信息的,排在同笔画数有笔顺
的字后面。使用部首和除部首笔画数排序时,部首按康熙字典 214 部首顺序排列,部首
和笔画数相同的按 Unicode 编码排序。

\subsection{页码排序与合并}
\label{subsec:pagemerge}

内容完全相同而页码不同的索引项,会在排序时合并为一项。同一索引项的所有页码会按
前后次序排序、去重,并按要求合并为页码区间。

\index{数字}
\index{页码}
\zhm 能识别不同类型的页码格式,包括阿拉伯数字(1, 2, 3, \ldots)、大小写罗马数
字(I, II, III, \ldots)、大小写拉丁字母(a, b, c, \ldots)。不同类型的页码按
照 \kw{page_precedence} 变量的设置(\autoref{tab:oldoutputstyle})区分前后次序。
默认情况下,不同类型的页码次序是 "rnaRA",即小写罗马数字的页码排在最前,然后依
次是阿拉伯数字、小写拉丁字母、大写罗马数字、大写拉丁字母的页码。

目前,页码的类型判别比较粗糙,仅以页码的第一个字符判断类型。当页码以字母 "i",
"v", "x", "l", "c", "d", "m" 起始时,即被识别为罗马数字,其他字母被识别为拉丁
字母页码。

\zhm 支持页码区间,在索引项中显式指定区间,如对输入
\begin{verbatim}
\indexentry{foo|(}{5}
\indexentry{foo|)}{10}
\end{verbatim}
则 "foo" 项会输出页码 5--10。连续的区间、区间内的零散页码会被合并为一个大的区
间,如对输入
\begin{verbatim}
\indexentry{foo|(}{5}
\indexentry{foo}{6}
\indexentry{foo|)}{10}
\indexentry{foo|(}{11}
\indexentry{foo|)}{13}
\end{verbatim}
则 "foo" 项会输出页码 5--13。

\optindex{-r}
如果没有使用 "-r" 选项(\ref{subsec:oldoption}~节),零散的页码也会与区间一起
合并,3 页或以上连续的页码也会被合并为区间。例如输入
\begin{verbatim}
\indexentry{foo}{i}
\indexentry{foo}{ii}
\indexentry{foo}{iii}
\indexentry{foo|(}{5}
\indexentry{foo|)}{7}
\indexentry{foo}{8}
\end{verbatim}
则 "foo" 项会输出页码 i--iii, 5--8。使用 "-r" 选项将禁止这种自动合并。

在排序合并页码时,\zhm 会区分不同数字类型的页码;如果页码还有特殊命令修饰,则
还会区分不同的修饰命令。例如输入
\begin{verbatim}
\indexentry{foo}{1}
\indexentry{foo|textit}{5}
\indexentry{foo}{3}
\indexentry{foo|textit}{7}
\end{verbatim}
则 "foo" 项会分别以不同格式输出页码 1, 3, \textit{5}, \textit{7}。

在页码区间中如果出现不同类型的特殊命令修饰,则按不同的页码格式分别输出。但是,
为了适应部分 \LaTeX{} 代码不精确的页码输出,如果页码区间头与页码区间尾使用的特
殊命令不同,仍把它们看做相同的格式,按页码区间头的格式输出。例如输入
\begin{verbatim}
\indexentry{foo|(textit}{1}
\indexentry{foo|textbf}{5}
\indexentry{foo|textit}{2}
\indexentry{foo|)}{4}
\end{verbatim}
则 "foo" 项会把页码 1, 2, 4 都归入区间 1--4,输出页码 \textit{1--4},
\textbf{5}。这也是 \pkg{makeindex} 默认效果。如果使用了 "-strict" 选项
(\ref{subsec:newoption}~节),则不再允许页码区间有不同的特殊命令修饰,而要求
格式严格匹配。"-strict" 选项适合用于不同格式页码区间相互交错的复杂的页码格式,
例如输入
\begin{verbatim}
\indexentry{foo|(textit}{1}
\indexentry{foo|(textbf}{5}
\indexentry{foo|)textit}{8}
\indexentry{foo|)textbf}{9}
\end{verbatim}
则 "foo" 项会输出页码 \textbf{5--9}, \textit{1--8}。但如果不使用 "-strict" 选
项,或者使用 \pkg{makeindex},则无法正确识别这类页码区间。

\section{与 \pkg{makeindex} 的比较}

\begin{itemize}
  \gooditem \zhm 支持 Unicode,所有字符按 Unicode 字符而非字节流处理。同时支持
  输入输出文件、格式文件使用不同的中文编码(\ref{subsec:newoption}~节)。

  \gooditem \zhm 支持中文特有的分组与排序方式(第~\ref{sec:sort} 节)。

  \gooditem \zhm 与 \pkg{makeindex} 的页码合并算法不同
  (\ref{subsec:pagemerge}~节),在页码区间有嵌套和交错,前后分界的格式不统一
  时,\zhm 与 \pkg{makeindex} 可能会产生不完全相同的效果。如果使用 "-strict"
  选项,\zhm 会使用更复杂的页码区间合并算法,能正确处理不同格式多层嵌套和互相
  交错的页码区间,也能识别输入不正确的前后区间分界,而 \pkg{makeindex} 将给出
  错误的结果。

  \gooditem \zhm 的格式文件支持使用反引号界定的串,在其中禁用转义符
  (第~\ref{sec:ist} 节)。

  \gooditem \zhm 对输入的索引文件支持单个注释符开始的行注释。

  \baditem \zhm 暂不支持 "-p" 选项自动获取 \TeX{} 编译日志文件中的页码,然后输出对
  应的页码设置语句(\ref{subsec:unsupportedoption}~节、
  \autoref{tab:unsupportedoutputstyle})。

  \baditem \zhm 不支持 "-g", "-l", "-L", "-T" 等与中文索引无关的语言选项。

  \baditem \zhm 不支持输出折行(\autoref{tab:unsupportedoutputstyle})。
\end{itemize}

\section{已知问题}

\index{多音字}
汉字按拼音分组排序时,多音字可能会被分到错误的分组或排在错误的位置。例如,“长
度”的“长”有 zhǎng 与 cháng 两个常用读音,由于读音 zhǎng 的使用频率比
cháng 略高一点,“长”字就会按 zhǎng 的读音分到 Z 组,排序也较为靠后。目前
\zhm 缺少一种通用的方式控制多音字按拼音分组与排序,只能暂时使用同音字处理此问
题。另外,部分汉字因为旧字形等问题,笔画数和笔顺也可能有多种选择,造成分组的分
歧。

\section{版权与许可}
\index{版权}\index{许可}

版权所有:2014, 2015, 2016, 2018 年,刘海洋 \email{leoliu.pku@gmail.com}

\index{LPPL}
本作品可在《the \LaTeX{} Project Public License》1.3 或更高版本的条件下发布与
修改。最新版本的 LPPL 许可证可以在
\begin{quote}
  \url{http://www.latex-project.org/lppl.txt}
\end{quote}
下载;该许可证同时也包含在所有最新的 \LaTeX{} 发行版中。

本作品目前处于 LPPL 维护状态“maintained”。

当前维护者是刘海洋。

\index{源文件}
本作品包括 \zhm 的程序及文档,由如下源文件:
\begin{verbatim}
build-dist.cmd
input.go
install.cmd
main.go
MENIFEST
numberedreader.go
output.go
pagenumber.go
radical_collator.go
reading_collator.go
README
sorter.go
stroke_collator.go
style.go
style_test.go
VERSION
doc/make.cmd
doc/zhmakeindex.bib
doc/zhmakeindex.mst
doc/zhmakeindex.tex
examples/compositepage.idx
examples/gb2312.idx
examples/mixedpage.idx
examples/numbers.idx
examples/rangeencap.idx
examples/suffix.ist
examples/symorder.idx
examples/zh.ist
kpathsea/dynamic_other.go
kpathsea/dynamic_windows_386.go
kpathsea/kpathsea.go
CJK/make-table.cmd
CJK/maketables.go
CJK/radicalstrokes.go
CJK/strokes.go
CJK/readings.go
\end{verbatim}
以及编译源文件得到的二进制文件 \path{zhmakeindex.exe} 或 \path{zhmakeindex}、
PDF 文档 \path{zhmakeindex.pdf} 组成。

\index{Unicode}
大部分汉字数据来自 Unicode 项目(\url{http://www.unicode.org/})。

\index{海峰五笔}
部分字形数据来自海峰五笔项目(\url{http://okuc.net/sunwb/}):
\begin{verbatim}
maketables/sunwb_strokeorder.txt
\end{verbatim}

\bibliography{zhmakeindex}

\printindex

\end{document}

vim:tw=78