我正在撰写博士论文,需要创建所有引用的主要来源的索引。我创建了“引用”命令,这样每当我引用以下内容时,它都会自动添加索引行:
\newcommand{\citeherm}[1]{\emph{Shepherd of Hermas}~#1\index{Shepherd of Hermas!#1}}
效果很好,只是索引的数字顺序不正确。'11' 会位于 '1' 和 '2' 之间,在这种情况下显然是不正确的。
我附上了一个最简单的例子。谁能帮忙?
(顺便说一句,我以为你可以通过使用不打印的运行零来手动完成此操作,但我不知道如何在上面的命令中自动执行此操作。
\index{Shepherd of Hermas!03.13–[email protected]–8}
)
最小示例
\documentclass[12pt]{memoir}
\newcommand{\citeherm}[1]{\emph{Shepherd of Hermas}~#1\index{Shepherd of Hermas!#1}}
\newcommand{\citeash}[1]{\emph{Testament of Asher}~#1\index{Testament of Asher!#1}}
\makeindex
\begin{document}
“bla bla bla” \citeherm{12.1}
“bla bla bla” \citeherm{12.2}
“bla bla bla” \citeherm{12.3}
“bla bla bla” \citeherm{12.4}
“bla bla bla” \citeherm{12.10}
“bla bla bla” \citeherm{12.11}
“bla bla bla” \citeherm{12.20}
“bla bla bla” \citeherm{12.21}
“bla bla bla” \citeash{1.1}
“bla bla bla” \citeash{2.1}
“bla bla bla” \citeash{10.1}
\printindex
\end{document}
答案1
我假设您的参考文献具有以下形式x.y-z
,可能省略了-z
部分,其中x
,y
和z
是小于 100 的数字:
\documentclass[12pt]{memoir}
\makeatletter
\def\bruin@normalize#1{\@bruin@normalizei#1-\@nil}
\def\@bruin@normalizei#1.#2-#3\@nil{%
\two@digits{#1}.\two@digits{#2}%
\if\relax\detokenize{#3}\relax\else
-\expandafter\two@digits\expandafter{\@gobblehyphen#3}%
\fi}
\def\@gobblehyphen#1-{#1}
\newcommand{\defcite}[2]{%
\newcommand{#1}[1]{\emph{#2}~##1\index{#2!\bruin@normalize{##1}@##1}}%
}
\makeatother
\defcite{\citeherm}{Shepherd of Hermas}
\defcite{\citeash}{Testament of Asher}
\makeindex
\begin{document}
bla bla bla \citeherm{12.1}
bla bla bla \citeherm{12.2}
bla bla bla \citeherm{12.3}
bla bla bla \citeherm{12.4}
bla bla bla \citeherm{12.10}
bla bla bla \citeherm{12.11}
bla bla bla \citeherm{12.20}
bla bla bla \citeherm{12.21}
bla bla bla \citeash{1.1}
bla bla bla \citeash{2.1}
bla bla bla \citeash{10.1}
\printindex
\end{document}
如果格式不同,则必须进行一些更正。例如,如果数字可以是三位数,则添加
\def\three@digits#1{\ifnum#1<1000 0\ifnum#1<10 0\fi\fi#1}
并使用\three@digits
代替\two@digits
。
我还定义了一个“catch-all”命令,用于统一定义索引命令。
添加:支持列表参数(和三位数字)
\makeatletter
\def\three@digits#1{\ifnum#1<100 0\ifnum#1<10 0\fi\fi#1}
\def\bruin@normalize#1{\@bruin@normalizei#1-\@nil}
\def\@bruin@normalizei#1.#2-#3\@nil{%
\three@digits{#1}.\three@digits{#2}%
\if\relax\detokenize{#3}\relax\else
-\expandafter\three@digits\expandafter{\@gobblehyphen#3}%
\fi}
\def\@gobblehyphen#1-{#1}
\newcommand{\defcite}[2]{%
\newcommand{#1}[1]{\emph{#2}\bruin@dolist{#2}{##1}}}
\def\bruin@dolist#1#2{%
\toks@={~\@gobbletwo}%
\@for\next:=#2\do{%
\edef\next{,\noexpand\space\next
\noexpand\index{#1!\expandafter\bruin@normalize\expandafter{\next}@\next}}%
\toks@=\expandafter{\the\expandafter\toks@\next}%
}\the\toks@
}
\makeatother
\defcite{\citeherm}{Shepherd of Hermas}
\defcite{\citeash}{Testament of Asher}
现在输入如下内容\citeherm{12.1,35.4,28.2}
将会打印
赫马牧人 12.1, 35.4, 28.2
在“Hermas”和第一个数字之间有一个不间断的空格;它将索引所有三个参考。
新增:支持章节范围
\makeatletter
\def\three@digits#1{\ifnum#1<100 0\ifnum#1<10 0\fi\fi#1}
\def\bruin@normalize#1{\@bruin@normalizei#1-.\@nil}
\def\@bruin@normalizei#1.#2-#3.#4\@nil{%
\three@digits{#1}.\three@digits{#2}%
\if\relax\detokenize{#4}\relax
% same chapter range
\if\relax\detokenize{#3}\relax
% simple range
% already set
\else
-\expandafter\three@digits\expandafter{\@gobblehyphen#3}%
\fi
\else
% different chapters range
-\three@digits{#3}.\expandafter\three@digits\expandafter{\@gobblehyphenperiod#4}%
\fi}
\def\@gobblehyphen#1-{#1}
\def\@gobblehyphenperiod#1-.{#1}
\newcommand{\defcite}[2]{%
\newcommand{#1}[1]{\emph{#2}\bruin@dolist{#2}{##1}}}
\def\bruin@dolist#1#2{%
\toks@={~\@gobbletwo}%
\@for\next:=#2\do{%
\edef\next{,\noexpand\space\next
\noexpand\index{#1!\expandafter\bruin@normalize\expandafter{\next}@\next}}%
\toks@=\expandafter{\the\expandafter\toks@\next}%
}\showthe\toks@\the\toks@
}
\makeatother
\defcite{\citeherm}{Shepherd of Hermas}
\defcite{\citeash}{Testament of Asher}
现在也\citeherm{1.2-3.4}
将被编入索引。列表将继续像以前一样工作。
新增:还支持简单引用
\makeatletter
\def\three@digits#1{\ifnum#1<100 0\ifnum#1<10 0\fi\fi#1}
\def\bruin@normalize#1{\@bruin@normalizei#1.\@nil}
\def\@bruin@normalizei#1.#2\@nil{%
\if\relax\detokenize{#2}\relax
% only one number
\three@digits{#1}\expandafter\@gobble
\else
\expandafter\@firstofone
\fi{\@bruin@gobbleperiod#1.#2\@nil}
}
\def\@bruin@gobbleperiod#1.\@nil{\@bruin@normalizeii#1-.\@nil}
\def\@bruin@normalizeii#1.#2-#3.#4\@nil{%
\three@digits{#1}.\three@digits{#2}%
\if\relax\detokenize{#4}\relax
% same chapter range
\if\relax\detokenize{#3}\relax
% simple range
% already set
\else
-\expandafter\three@digits\expandafter{\@gobblehyphen#3}%
\fi
\else
% different chapters range
-\three@digits{#3}.\expandafter\three@digits\expandafter{\@gobblehyphenperiod#4}%
\fi}
\def\@gobblehyphen#1-{#1}
\def\@gobblehyphenperiod#1-.{#1}
\newcommand{\defcite}[2]{%
\newcommand{#1}[1]{\emph{#2}\bruin@dolist{#2}{##1}}}
\def\bruin@dolist#1#2{%
\toks@={~\@gobbletwo}%
\@for\next:=#2\do{%
\edef\next{,\noexpand\space\next
\noexpand\index{#1!\expandafter\bruin@normalize\expandafter{\next}@\next}}%
\toks@=\expandafter{\the\expandafter\toks@\next}%
}\the\toks@
}
\makeatother
\defcite{\citeherm}{Shepherd of Hermas}
\defcite{\citeash}{Testament of Asher}
这也应该允许类似引用\citeherm{12}
。
最后(?)补充
这是一个“LaTeX3”的实现:
\documentclass[12pt]{memoir}
\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \l_bruin_argi_tl
\tl_new:N \l_bruin_argii_tl
\tl_new:N \l_bruin_argx_tl
\tl_new:N \l_bruin_temp_tl
\tl_new:N \l_bruin_final_tl
% First of all we split the comma separated list; we store |#1|, the
% title of the book, in |\bruin_argi_tl| and |\bruin_argx_tl| to
% contain |\use_none:nn| that at the end will gobble the first two
% tokens (a comma and a space); then we put the split list of
% arguments followed by |{\NoValue}| after |\bruin_process:n|, because
% it will be used to terminate the recursion.
\NewDocumentCommand\bruin_dolist:nn {m >{\SplitList{,}}m}{
\tl_set:Nn \l_bruin_argi_tl { #1 }
\tl_set:Nn \l_bruin_argx_tl { \use_none:nn }
\bruin_process:n #2 {\NoValue}
}
% |\bruin_process:n| initiates the recursion; it examines the contents
% of the first pair of braces after it and, if different from
% |\NoValue|, stores it into |\bruin_argii_tl|. Then it appends also
% it to the list |\bruin_argx_tl|, after a comma and a space. The same
% contents is also processed by |\bruin_normalize:n|. Then we execute
% |\bruin_do:| and call again |\bruin_process:n| to restart the recursion.
\cs_new:Nn \bruin_process:n {
\IfNoValueTF{#1}
{}% end of recursion
{
\tl_set:Nn \l_bruin_argii_tl {#1}
\tl_set:Nx \l_bruin_argx_tl { \l_bruin_argx_tl , \c_space_tl #1 }
\bruin_normalize:n {#1} \bruin_do: \bruin_process:n
}
}
% |\bruin_normalize:n| is responsible for splitting an entry of the
% form |A-B| (|A| and |B| will actually be something like |1.2|) into
% the two components, which are passed to |\bruin_normalizei:nn|
\NewDocumentCommand\bruin_normalize:n {>{\SplitArgument{1}{-}}m}{
\bruin_normalizei:nn #1
}
% If the entry was |A-B|, |\bruin_normalizei:nn| is passed |{A}{B}|,
% otherwise it is passed |{A}{\NoValue}|
\cs_new:Nn \bruin_normalizei:nn {
\IfNoValueTF{#2}
{\bruin_three:n {#1}} % simple entry
{\bruin_three:nn {#1}{#2}} % complex entry
}
% |\bruin_three:n| splits an argument of the form |1.2.3| into the
% components; it's quite similar to |\bruin_normalize:n|
\NewDocumentCommand\bruin_three:n {>{\SplitArgument{2}{.}}m}{
\bruin_threedo:nnn #1
\tl_set:Nx \l_bruin_final_tl {\l_bruin_temp_tl}
}
% |\bruin_threedo:nnn| sets |\l_bruin_final_tl| to the components but
% with three digits; |1| is transformed into |001| and |1.2| becomes
% |001.002|, while |1.2.3| becomes |001.002.003|
\cs_new:Nn \bruin_threedo:nnn {
\IfNoValueTF{#3}
{\IfNoValueTF{#2}
{\tl_set:Nx \l_bruin_temp_tl
{\bruin_threedig:n{#1}}}
{\tl_set:Nx \l_bruin_temp_tl
{\bruin_threedig:n{#1}.\bruin_threedig:n{#2}}}
}
{\tl_set:Nx \l_bruin_temp_tl
{\bruin_threedig:n{#1}.\bruin_threedig:n{#2}.\bruin_threedig:n{#3}}
}
}
% we do similarly for |\bruin_three:nn|, calling |\bruin_threedo:nnn| twice.
\NewDocumentCommand\bruin_three:nn
{>{\SplitArgument{2}{.}}m >{\SplitArgument{2}{.}}m}
{ \bruin_threedo:nnn #1
\tl_set:Nx \l_bruin_final_tl {\l_bruin_temp_tl }
\bruin_threedo:nnn #2
\tl_set:Nx \l_bruin_final_tl {\l_bruin_final_tl -- \l_bruin_temp_tl}
}
\cs_new:Nn \bruin_do: {
\cs_set:Nx \bruin_next: {
\exp_not:N \index
{\l_bruin_argi_tl ! \l_bruin_final_tl \c_space_tl @ \l_bruin_argii_tl }
}
\bruin_next:
}
\cs_new:Nn \bruin_threedig:n {
\int_compare:nNnTF {#1} < {100}
{ 0 \int_compare:nNnTF {#1} < {10} {0}{} }
{} #1
}
% |\bruin_defcite:nn| defines |#1| as a macro with one argument, first
% storing its second argument in it. So
%
% |\defcite{\citeT}{Title}|
%
% defines |\citeT| as if it were
%
% |\def\citeT#1{\emph{Title}\space\bruin_dolist:nn{Title}{#1}\l_bruin_argx_tl}|
%
% The token list |\l_bruin_argx_tl| will be built by |\bruin_dolist:nn|
\cs_new:Nn \bruin_defcite:nn {
\cs_new:Npn #1##1{\emph{#2}\space\bruin_dolist:nn {#2}{##1} \l_bruin_argx_tl }}
\cs_set_eq:NN \defcite \bruin_defcite:nn
\ExplSyntaxOff
\defcite{\citeherm}{Shepherd of Hermas}
\defcite{\citeash}{Testament of Asher}
\makeindex
\begin{document}
%\tracingmacros=1
bla bla bla \citeherm{12.1-2}
\newpage
bla bla bla \citeherm{12.2,13.9}
\newpage
bla bla bla \citeherm{12.3-13.4}
\newpage
bla bla bla \citeherm{12}
\newpage
bla bla bla \citeherm{12.10}
\newpage
bla bla bla \citeherm{12.11}
\newpage
bla bla bla \citeherm{12.20}
\newpage
bla bla bla \citeherm{12.21}
\newpage
bla bla bla \citeash{1.2.3}
\newpage
bla bla bla \citeash{2.1}.
\newpage
bla bla bla \citeash{10.1,1.1,2.9-19}.
\newpage
\printindex
\end{document}
正如您在示例中看到的,这也应该支持三个级别\citeash
。
LaTeX3 2012 年 7 月更新后的版本
\documentclass[12pt]{memoir}
\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \l_bruin_argi_tl
\tl_new:N \l_bruin_argii_tl
\tl_new:N \l_bruin_argx_tl
\tl_new:N \l_bruin_temp_tl
\tl_new:N \l_bruin_final_tl
% First of all we split the comma separated list; we store |#1|, the
% title of the book, in |\bruin_argi_tl| and |\bruin_argx_tl| to
% contain |\use_none:nn| that at the end will gobble the first two
% tokens (a comma and a space); then we put the split list of
% arguments followed by |{\NoValue}| after |\bruin_process:n|, because
% it will be used to terminate the recursion.
\NewDocumentCommand\bruin_dolist:nn {m >{\SplitList{,}}m}{
\tl_set:Nn \l_bruin_argi_tl { #1 }
\tl_set:Nn \l_bruin_argx_tl { \use_none:nn }
\ProcessList{#2}{\bruin_process:n}
}
% |\bruin_process:n| does the recursion via \ProcessList; it
% stores its argument into |\bruin_argii_tl|. Then it appends also
% it to the list |\bruin_argx_tl|, after a comma and a space. The same
% contents is also processed by |\bruin_normalize:n|. Then we execute
% |\bruin_do:|.
\cs_new:Nn \bruin_process:n {
\tl_set:Nn \l_bruin_argii_tl {#1}
\tl_set:Nx \l_bruin_argx_tl { \l_bruin_argx_tl , \c_space_tl #1 }
\bruin_normalize:n {#1} \bruin_do:
}
% |\bruin_normalize:n| is responsible for splitting an entry of the
% form |A-B| (|A| and |B| will actually be something like |1.2|) into
% the two components, which are passed to |\bruin_normalizei:nn|
\NewDocumentCommand\bruin_normalize:n {>{\SplitArgument{1}{-}}m}{
\bruin_normalizei:nn #1
}
% If the entry was |A-B|, |\bruin_normalizei:nn| is passed |{A}{B}|,
% otherwise it is passed |{A}{\NoValue}|
\cs_new:Nn \bruin_normalizei:nn {
\IfNoValueTF{#2}
{\bruin_three:n {#1}} % simple entry
{\bruin_three:nn {#1}{#2}} % complex entry
}
% |\bruin_three:n| splits an argument of the form |1.2.3| into the
% components; it's quite similar to |\bruin_normalize:n|
\NewDocumentCommand\bruin_three:n {>{\SplitArgument{2}{.}}m}{
\bruin_threedo:nnn #1
\tl_set:Nx \l_bruin_final_tl {\l_bruin_temp_tl}
}
% |\bruin_threedo:nnn| sets |\l_bruin_final_tl| to the components but
% with three digits; |1| is transformed into |001| and |1.2| becomes
% |001.002|, while |1.2.3| becomes |001.002.003|
\cs_new:Nn \bruin_threedo:nnn {
\IfNoValueTF{#3}
{\IfNoValueTF{#2}
{\tl_set:Nx \l_bruin_temp_tl
{\bruin_threedig:n{#1}}}
{\tl_set:Nx \l_bruin_temp_tl
{\bruin_threedig:n{#1}.\bruin_threedig:n{#2}}}
}
{\tl_set:Nx \l_bruin_temp_tl
{\bruin_threedig:n{#1}.\bruin_threedig:n{#2}.\bruin_threedig:n{#3}}
}
}
% we do similarly for |\bruin_three:nn|, calling |\bruin_threedo:nnn| twice.
\NewDocumentCommand\bruin_three:nn
{>{\SplitArgument{2}{.}}m >{\SplitArgument{2}{.}}m}
{ \bruin_threedo:nnn #1
\tl_set:Nx \l_bruin_final_tl {\l_bruin_temp_tl }
\bruin_threedo:nnn #2
\tl_set:Nx \l_bruin_final_tl {\l_bruin_final_tl -- \l_bruin_temp_tl}
}
\cs_new:Nn \bruin_do: {
\cs_set:Nx \bruin_next: {
\exp_not:N \index
{\l_bruin_argi_tl ! \l_bruin_final_tl \c_space_tl @ \l_bruin_argii_tl }
}
\bruin_next:
}
\cs_new:Nn \bruin_threedig:n {
\int_compare:nNnTF {#1} < {100}
{ 0 \int_compare:nNnTF {#1} < {10} {0}{} }
{} #1
}
% |\bruin_defcite:nn| defines |#1| as a macro with one argument, first
% storing its second argument in it. So
%
% |\defcite{\citeT}{Title}|
%
% defines |\citeT| as if it were
%
% |\def\citeT#1{\emph{Title}\space\bruin_dolist:nn{Title}{#1}\l_bruin_argx_tl}|
%
% The token list |\l_bruin_argx_tl| will be built by |\bruin_dolist:nn|
\cs_new:Nn \bruin_defcite:nn {
\cs_new:Npn #1##1{\emph{#2}\space\bruin_dolist:nn {#2}{##1} \l_bruin_argx_tl }}
\cs_set_eq:NN \defcite \bruin_defcite:nn
\ExplSyntaxOff
\defcite{\citeherm}{Shepherd of Hermas}
\defcite{\citeash}{Testament of Asher}
\makeindex
\begin{document}
%\tracingmacros=1
bla bla bla \citeherm{12.1-2}
\newpage
bla bla bla \citeherm{12.2,13.9}
\newpage
bla bla bla \citeherm{12.3-13.4}
\newpage
bla bla bla \citeherm{12}
\newpage
bla bla bla \citeherm{12.10}
\newpage
bla bla bla \citeherm{12.11}
\newpage
bla bla bla \citeherm{12.20}
\newpage
bla bla bla \citeherm{12.21}
\newpage
bla bla bla \citeash{1.2.3}
\newpage
bla bla bla \citeash{2.1}.
\newpage
bla bla bla \citeash{10.1,1.1,2.9-19}.
\newpage
\printindex
\end{document}