如何在 \index 命令中强制扩展宏

如何在 \index 命令中强制扩展宏

我想强制扩展 \index 命令中的宏。这是一个最小示例:

\documentclass{book}
\usepackage{makeidx}
\makeindex

\begin{document}
Text. Text. Text. Text. Text. Text. \index{page number \arabic{page}} Text. Text. Text.
\printindex
\end{document}

编译后,索引位于第 2 页,索引条目为“页码 2,1”。

我想要的是它读取“页码 1,1”,因为命令是在第 1 页发出的。

感谢您的帮助。

答案1

我通常不需要一个索引条目来告诉我编号为 1 的页面可以在第 1 页上找到。;-)

你为什么想要这样的东西?

是因为它可能。

让我们对这个问题进行一次模拟辩论。

你会面临几个问题:

  1. 通常,您无法预测当前处理的材料最终会出现在 LaTeX 当前即将构建的页面上还是会出现在下一页上。
    您可以依靠\arabic{page}得出 LaTeX 当前即将构建的页面编号,但无法预测您尝试通过此表达式表示的材料最终会出现在 LaTeX 当前即将构建的页面上还是会出现在该页面之后的页面上。

    因此,您通常需要使用\label..\pageref机制或其衍生机制之一,通过命名相关内容出现的页码来表示事物。

  2. -macro\index会尝试阻止材料进入索引条目/进入 .idx 文件,并通过制作索引用于排序和创建 .ind 文件以防止其被展开。
    如果您通过 查看其定义,\show\index您会发现它(通过\@sanitize)使用了一些 catcode 技巧,以确保通常用于单个控制序列标记的内容将用于普通字符标记序列。
    例如,\macro不应将其用于控制​​序列标记,\macro但应将其用于字符标记序列\, m, a, c, ro

    你需要推翻这些阻止扩张的尝试,因为

    • 您不希望所有这些索引条目都按以下方式排序,page number \arabic{page}但您希望它们按以下方式排序page number 1:,,page number 2...
    • 您不希望它们的扩展被延迟,直到\printindex处理完 .ind 文件之后,因为这样,所有这些条目都会产生页码计数器在打印索引中出现相应索引条目的那部分时所具有的编号,而不是在文档正文中可以找到相应材料的页面的编号。
  3. 您需要注意在放置和紧跟彼此时所做的\@bsphack.. -thingie。\@esphack\label\index\label\index

我可以提供一个繁琐的方法,其中\getrefbykeydefault-macro 的引用计数Heiko Oberdiek 编写的包用于引用页码(该宏需要两次扩展/两次“命中”才能提供所需的值),并且和自制宏\expandafter的组合用于覆盖的扩展预防并获取在处理命令时立即来自..引用的数值。 (仅用于触发扩展。它以不传递任何令牌的方式使用。)\expandafter\romannumeral\ExchangeWithFirstExpanded\index\label\pageref/\getrefbykeydefault\index\romannumeral

LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right您需要确保在第一次调用之前编译代码多次,直到不再收到警告制作索引否则索引条目将不会由正确的短语形成。

我决定将创建引用标签和索引条目的命令放入其自己的宏中:

\documentclass{book}

\makeatletter
% \romannumeral\ExchangeWithFirstExpanded{<k>}{<first>}{<second>}
% yields:
% <second>< <first> "hit" k times by \expandafter >
\newcommand\@exchange[2]{#2#1}%
\newcommand*\@innerdfork{}%
\def\@innerdfork#1d#2#3dd{#2}%
\newcommand*\@dfork[1]{\@innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd}%
\newcommand\ExchangeWithFirstExpanded[3]{%
  0\expandafter\@exchange\expandafter{\romannumeral\number\number#1 000d}{\@innerExp{}{#2}{#3}}%
}%
\newcommand\@innerExp[4]{%
  \@dfork{#4}{#1\@exchange#1{#2}{ #3}}{\@innerExp{#1#1\expandafter}{#2}{#3}}%
}%

% 
%\PageNuberAlsoInIndexEntry{<name of to be placed referencing label>}
%
\newcommand\PageNuberAlsoInIndexEntry[1]{%
  \label{#1}% <-This will - due to \@esphack - switch \lastskip to 0, so we need a trick for restoring \lastskip:
  \ifhmode\nobreak\hskip-\@savsk\nobreak\hskip\@savsk\fi
  \expandafter\index
    \expandafter{\romannumeral\ExchangeWithFirstExpanded{2}{\getrefbykeydefault{#1}{page}{0}}{page number }%
  }%
}%
\makeatother

\usepackage{makeidx}
\usepackage{refcount}

\makeindex

\begin{document}
Text. Text. Text. Text. Text. Text. \PageNuberAlsoInIndexEntry{NicePage} Text. Text. Text.
\printindex
\end{document}

在此处输入图片描述

在此处输入图片描述



从你的评论来看

最初的问题是这样的:我们正在将一本书从英语翻译成法语,这本书可能有 100 页的尾注。尾注中的名字在索引中是这样引用的:Pythagoras, 412n35,意思是“第 35 号尾注,第 412 页”。

我了解到问题似乎不在于扩展\index命令内的材料,而在于在索引条目中提供正确的语法:

有一个|带有索引条目的东西制作索引-程序:

\index{Pythagoras|bar}表示属于索引条目的页码毕达哥拉斯\bar由于要\printindex打印索引条目,因此将被包装到when 中。这意味着您将得到类似以下内容的内容:
Pythagoras \bar{412},。

您可以使用此功能并

  1. 定义一个宏\bar,它将在前面添加字母n和-counter 的值endnote

  2. 定义您自己的\index-command 变体,它会自动附加|bar内容。

在下面的例子中,我这样做了,并且还尝试添加一些对超链接-包裹。

后者意味着我必须修补/重新定义一些内部宏尾注-包裹。

加载时超链接-package(是否加载由您决定):

\endnote将获得一个带有尾注标记的尾注,该尾注具有指向尾注文本的链接。

\endnote*将获得一个没有尾注标记的尾注,但有一个指向尾注文本的链接。

在你\IndexWithEndnotemark{index entry}的论点里面\endnote,在(重新)运行之后制作索引,获取一个索引条目,其中字母n和计数器的值endnote附加到页码,并且此页码构造包装到指向相应尾注文本的超链接中。

在你\IndexWithEndnotemark*{index entry}的论点里面\endnote,在(重新)运行之后制作索引,获取一个索引条目,其中字母n和计数器的值endnote附加到页码,并且此页码构造不包装在超链接中。

当不加载超链接-package 您永远不会获得超链接。

\documentclass{book}

\makeatletter
% This must take place before loading hyperref.
\newcommand\MySaved@Wrindex@NoHyperref{}%
\let\MySaved@Wrindex@NoHyperref=\@wrindex
\makeatother

\usepackage{makeidx}
\usepackage{endnotes}
\usepackage{hyperref}

\makeatletter
\newcounter{totalendnotes}%
\newcommand*\savedendnote{}%
\let\savedendnote\endnote
\newcommand*\savedendnotemark{}%
\let\savedendnotemark\endnotemark
\newcommand\savedbaselineskip{}%
\newcommand\numberofendnoteanchor{}%
\newcommand\hypercommandforendnote[2]{#2}%
\newcommand\IndexWithEndnotemark@index{}%
\let\IndexWithEndnotemark@index=\index
%%
%%  \IndexWithEndnotemark{index entry}
%%
\newcommand\IndexWithEndnotemark{%
  \@bsphack
  \begingroup\@sanitize
  \@ifstar\@IndexWithEndnotemarkAtStar\@IndexWithEndnotemarkAtNoStar
}%
\newcommand\@IndexWithEndnotemarkAtStar[1]{%
  \ifx\IndexWithEndnotemark@index\index
     \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  \@index\MySaved@Wrindex@NoHyperref{#1|addtheenmarkAtStar{n}{\@theenmark}{\numberofendnoteanchor}}%
}%
\newcommand*\addtheenmarkAtStar[4]{#4#1#2}%
\newcommand\@IndexWithEndnotemarkAtNoStar[1]{%
  \ifx\IndexWithEndnotemark@index\index
     \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  \@index\MySaved@Wrindex@NoHyperref{#1|addtheenmarkAtNoStar{n}{\@theenmark}{\numberofendnoteanchor}}%
}%
\newcommand*\addtheenmarkAtNoStar[4]{\sethypercommandforendnote{\hyperlink{endnote:#3}}{#4#1#2}}%
%
\AtBeginDocument{%
  \@ifpackageloaded{hyperref}{%
    \newcommand\sethypercommandforendnote[1]{#1}%
  }{%
    \newcommand\sethypercommandforendnote[1]{}%
  }%
}%
%
\def\endnote{%
  \stepcounter{totalendnotes}%
  \def\numberofendnoteanchor{\thetotalendnotes}%
  \@ifstar{%
    \savedendnote
  }{%
    \sethypercommandforendnote{\def\hypercommandforendnote{\hyperlink}}%
    \savedendnote
  }%
}%
\def\endnotemark{%
   \stepcounter{totalendnotes}%
   \def\numberofendnoteanchor{\thetotalendnotes}%
   \@ifstar{%
     \savedendnotemark
   }{%
     \sethypercommandforendnote{\def\hypercommandforendnote{\hyperlink}}%
     \savedendnotemark
   }%
}%
\def\@makeenmark{%
  \hbox{%
    \@textsuperscript{%
      \normalfont
      \hypercommandforendnote{endnote:\numberofendnoteanchor}{\@theenmark}%
     }%
   }%
}%
\long\def\@endnotetext#1{%
     \if@enotesopen \else \@openenotes \fi
     \immediate\write\@enotes{\@doanenote{\@theenmark}{\thetotalendnotes}}%
     \begingroup
        \def\next{#1}%
        \newlinechar='40
        \immediate\write\@enotes{\meaning\next}%
     \endgroup
     \immediate\write\@enotes{\@endanenote}%
}%
\def\theendnotes{\immediate\closeout\@enotes \global\@enotesopenfalse
  \begingroup
    \edef\savedbaselineskip{\the\baselineskip}%
    \makeatletter
    \edef\@tempa{`\string >}%
    \ifnum\catcode\@tempa=12%
      \let\@ResetGT\relax
    \else
      \edef\@ResetGT{\noexpand\catcode\@tempa=\the\catcode\@tempa}%
      \@makeother\>%
    \fi
    \def\@doanenote##1##2##3>{\def\@theenmark{##1}\par\begingroup
        \@ResetGT
        \def\numberofendnoteanchor{##2}%
        \sethypercommandforendnote{%
          \def\hypercommandforendnote####1####2{%
            {%
              \def\HyperRaiseLinkHook{%
                \setlength\HyperRaiseLinkLength{\savedbaselineskip}%
                \setlength\HyperRaiseLinkLength{.5\HyperRaiseLinkLength}%
              }%
              \Hy@raisedlink{\hypertarget{####1}{}}%
            }%
            ####2%
          }%
        }%
        \edef\@currentlabel{\csname p@endnote\endcsname\@theenmark}%
        \enoteformat}
    \def\@endanenote{\par\endgroup}%
    \enoteheading
    \enotesize
    \input{\jobname.ent}%
  \endgroup
}%
\makeatother

\makeindex

\begin{document}
Some drivel about Pythagoras.%
\endnote{\IndexWithEndnotemark{Pythagoras}The first endnote related to drivel about Pythagoras.}

Some more drivel about Pythagoras.%
\endnote{\IndexWithEndnotemark{Pythagoras}The second endnote related to drivel about Pythagoras.}

\theendnotes

\printindex
\end{document}

在此处输入图片描述

在此处输入图片描述

相关内容