我无法自己解决这个问题,也无法通过搜索这个很棒的网站来解决这个问题。问题在于索引。我仍然认为自己是 LaTeX 新手 :)
情况:
- 我正在写一本关于编程的英文书(300 多页)。为此,我使用制作idx和变量索引包;它们很棒并且运行良好。——这本书中有许多宏,例如,,,,\type{std:integer}
等等。它们只是提供正确的文本格式,没有什么神奇之处\var{variable}
。\const{SIZE}
\kword{for}
我想要的是 - 我想使用这些宏来索引所有这些词,以进行一级或二级索引。一些问题在这篇文章的末尾。
我做了什么:
- 我将所有宏(\type{}
、\const{}
等)更改为版本,其中还包括\index{#1}
,这非常简单。以下是示例:
\newcommand{\type}[1]{
\mbox{\texttt{#1}\index{#1}}
}
这给了我一个简单的索引,而且它运行良好。但是,在索引中,我有许多变量、常量和类型的长列表,它们都以相同的前缀开头,即cl::Source
、cl::Program
、 或CL_xxx
、CL_yyy
等。
我的尝试:
我想创建一个索引,主要单词是 cl::,所有以 cl:: 开头的单词都作为子项放在其下。这可以手动完成,也需要大量编辑,但我找到了字符串封装和\StrBehind
功能。
因此,我按以下方式定义宏:
\newcommand{\typei}[1]{%
\IfBeginWith{#1}{cl}{%
\IfBeginWith{#1}{cl::}
{\mbox{\texttt{#1}}\index{cl::!\StrBehind{#1}{cl::}}}
{\mbox{\texttt{#1}}\index{cl!#1}}
}{%
\IfBeginWith{#1}{CL}{%
\IfBeginWith{#1}{CL\_}
{\mbox{\texttt{#1}}\index{CL\_!\StrBehind{#1}{CL\_}}}
{\mbox{\texttt{#1}}\index{CL!#1}}
}%
{%
\mbox{\texttt{#1}}\I{#1}%
}%
}%
}
这(可能)导致了 LaTeX 错误:
! TeX capacity exceeded, sorry [input stack size=5000].
\reserved@a ->\def \reserved@a
*{\let \@xs@assign \@xs@expand@and@detokenize...
l.1127 ...nstructor of the type \typei{cl::Source}
and then the source is pa...
! ==> Fatal error occurred, no output PDF file produced!
所以我有一个相当普遍的问题:
如何定义一个宏,该宏可以索引具有给定起始字符的任何单词,并将该起始字符与其余部分分开以进行两级索引?我的意思是以下内容:
\type{cl::Type}
将产生类似的效果\texttt{cl::Type}\index{cl::!Type}
。最好是宏默认cl::
与其余部分分开,并且应该像平常一样对任何其他单词起作用。如何为不同类型的使用制作这样的宏?我宁愿避免为、、、、等输入所有非常相似的宏
\kword
-\var
它们都非常相似,只是排版不同。也许这是一种编写类似宏来生成另一个宏的方法\const
?\type
\func
理想的解决方案将允许使用一些预定义的前缀来索引单词,例如
std::
,,cl::
或CL_
......这将非常有帮助。
为这样的一本书编制索引是一项艰巨的任务,我有点不知所措。仅使用\index{}
命令也会弄乱正常文本。使用变量索引包通过定义循环引用和交叉引用大大改善了索引,这些引用非常可定制。整个包有点难以理解,但有很多可能性。也许有一些 hacky 方法可以让它变得简单?
抱歉发了这么长的帖子,我试图把事情说得尽可能清楚。我指望你们的帮助,*TeX
黑客们!:) 你们是我唯一的希望!:)
答案1
您的宏的实现\type
可以如下:
\documentclass[a4paper]{book}
\usepackage[T1]{fontenc}
\usepackage{xstring,imakeidx}
\makeindex
\makeatletter
\def\pi@tryprefix#1{%
\if@tempswa\else
\IfBeginWith{\pi@temp}{#1}{\@tempswatrue\def\pi@prefix{#1}}{}%
\fi}
\def\pi@protect{\noexpand\string\noexpand\detokenize}
\newcommand{\type}[1]{%
% normalize string
\edef\pi@temp{\detokenize{#1}}\def\pi@prefix{}%
% print the string
\texttt{\pi@temp}%
% look for a prefix
\@tempswafalse
\expandafter\pi@tryprefix\expandafter{\detokenize{cl::}}%
\expandafter\pi@tryprefix\expandafter{\detokenize{CL_}}%
%%%
% Add here other prefixes
%%%
\if@tempswa
\StrBehind{\pi@temp}{\pi@prefix}[\pi@temp]%
\begingroup\edef\x{\endgroup
\noexpand\index{\pi@prefix @\pi@protect{\pi@prefix}!\pi@temp @\pi@protect{\pi@temp}}}\x
\else
\begingroup\edef\x{\endgroup
\noexpand\index{\pi@temp @\pi@protect{\pi@temp}}}\x
\fi
}
\makeatother
\begin{document}
\type{cl::Type}
\type{CL_Type}
\type{CL_xyz}
\type{cc_yy}
\printindex
\end{document}
以下是该文件的内容.idx
:
\indexentry{cl::@\detokenize{cl::}!Type@\detokenize{Type}}{1}
\indexentry{CL_@\detokenize{CL_}!Type@\detokenize{Type}}{1}
\indexentry{CL_@\detokenize{CL_}!xyz@\detokenize{xyz}}{1}
\indexentry{cc_yy@\detokenize{cc_yy}}{1}
所有这些\detokenize
只是为了保护,_
以便您不必将其输入为\_
。
编辑:为了支持\type{CL\_Type}
,修改宏如下
\makeatletter
\def\pi@tryprefix#1{%
\if@tempswa\else
\IfBeginWith{\pi@temp}{#1}{\@tempswatrue\def\pi@prefix{#1}\let\pi@prefixp\pi@prefix}{}%
\expandafter\IfEndWith\expandafter\pi@prefix\expandafter{\detokenize{\_}}%
{\StrBefore{\pi@prefix}{\string\_}[\pi@prefixp]\edef\pi@prefixp{\pi@prefixp\string_}}{}%
\fi}
\def\pi@protect{\noexpand\string\noexpand\detokenize}
\newcommand{\type}[1]{%
% normalize string
\edef\pi@temp{\detokenize{#1}}\def\pi@prefix{}%
% print the string
\texttt{\pi@temp}%
% look for a prefix
\@tempswafalse
\expandafter\pi@tryprefix\expandafter{\detokenize{cl::}}%
\expandafter\pi@tryprefix\expandafter{\detokenize{CL_}}%
\expandafter\pi@tryprefix\expandafter{\detokenize{CL\_}}%
%%%
% Add here other prefixes
%%%
\if@tempswa
\StrBehind{\pi@temp}{\pi@prefix}[\pi@temp]%
\begingroup\edef\x{\endgroup
\noexpand\index{\pi@prefixp @\pi@protect{\pi@prefixp}!\pi@temp @\pi@protect{\pi@temp}}}\x
\else
\begingroup\edef\x{\endgroup
\noexpand\index{\pi@temp @\pi@protect{\pi@temp}}}\x
\fi
}
\makeatother
EDIT2:处理\_
字符串的另一种方法
\makeatletter
\def\pi@tryprefix#1{%
\if@tempswa\else
\IfBeginWith{\pi@temp}{#1}{\@tempswatrue\def\pi@prefix{#1}}{}%
\fi}
\def\pi@protect{\noexpand\string\noexpand\detokenize}
\newcommand{\type}[1]{%
% normalize string
\begingroup\edef\_{\string_}\edef\x{\endgroup\def\noexpand\pi@temp{#1}}\x
\edef\pi@temp{\detokenize\expandafter{\pi@temp}}\def\pi@prefix{}%
% print the string
\texttt{\pi@temp}%
% look for a prefix
\@tempswafalse
\expandafter\pi@tryprefix\expandafter{\detokenize{cl::}}%
\expandafter\pi@tryprefix\expandafter{\detokenize{CL_}}%
%%%
% Add here other prefixes
%%%
\if@tempswa
\StrBehind{\pi@temp}{\pi@prefix}[\pi@temp]%
\begingroup\edef\x{\endgroup
\noexpand\index{\pi@prefix @\pi@protect{\pi@prefix}!\pi@temp @\pi@protect{\pi@temp}}}\x
\else
\begingroup\edef\x{\endgroup
\noexpand\index{\pi@temp @\pi@protect{\pi@temp}}}\x
\fi
}
\makeatother
现在,在处理之前,所有内容\_
都会被转换为_
,因此无需查找前缀CL\_
,而只需查找CL_
。但是\_{}
必须将其更改为。支持\_
多个,但的参数中只允许包含字母数字字符和或的字符串。_
_
\_
\type
答案2
不确定您是否明白您想要什么。 也许这个 MWE 可以帮助您:
\documentclass{article}
\usepackage{xstring}
\usepackage{makeidx}
\makeindex
\newcommand\typei[1]{%
\def\printentry{#1}%
\IfBeginWith{#1}{cl}
{\IfBeginWith{#1}{cl::}
{\StrSubstitute[1]{#1}{cl::}{cl::!}[\newentry]}
{\StrSubstitute[1]{#1}{cl}{cl!}[\newentry]}%
}
{\IfBeginWith{#1}{CL}
{\IfBeginWith{#1}{CL_}
{\StrSubstitute[1]{#1}{CL_}{CL\_!}[\newentry]%
\StrSubstitute{#1}{_}{\_}[\printentry]%
}
{\StrSubstitute[1]{#1}{CL}{CL!}[\newentry]}%
}%
{\def\newentry{#1}}%
}%
\texttt{\printentry}%
\expandafter\index\expandafter{\newentry}%
}
\begin{document}
\noexpandarg
First is \typei{clfoo}, then \typei{cl::bar}.
After, there is \typei{CLone} and \typei{CL_two}!
Finaly: \typei{foobar}
\printindex
\end{document}
编辑:这是一个更完整的解决方案,您可以在其中定义一个以逗号分隔的前缀列表,例如x[y]
其中x
是强制部分和y
可选部分:
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{xstring}
\usepackage{makeidx}
\makeindex
\def\prefixlist{cl[::],foo[_],a[//],zoo[]}
\makeatletter
\newcommand\Idx[2][\texttt]{%
\def\argument@{#2}\let\prefix\@empty \let\sublevel\@empty \let\suffix\@empty
\saveexpandmode \expandarg
\expandafter\Idx@i\prefixlist,\@nil
#1{\prefix\suffix}% prints the entry with the macro #1
\index{\prefix\sublevel\suffix}%
\restoreexpandmode
}
\def\Idx@i#1[#2],#3\@nil{%
\IfBeginWith\argument@{\@empty#1}
{\IfBeginWith\argument@{\@empty#1#2}
{\def\sublevel{!}%
\def\prefix{\protect\detokenize{#1#2}}%
\StrBehind\argument@{\@empty#1#2}[\suffix]%
}
{\def\prefix{\protect\detokenize{#1}}%
\StrBehind\argument@{\@empty#1}[\suffix]%
}%
\ifx\suffix\@empty
\let\sublevel\@empty
\else
\edef\suffix{\noexpand\protect\noexpand\detokenize{\suffix}}%
\fi
}
{\ifx\@empty#3\@empty\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\edef\prefix{\noexpand\protect\noexpand\detokenize{\argument@}}}
{\Idx@i#3\@nil}%
}%
}
\makeatother
\newcommand\type{\Idx}
\newcommand\const{\Idx[\fbox]}
\newcommand\word{\Idx[\quoteword]}
\newcommand\quoteword[1]{"\textit{\bfseries#1}"}
\begin{document}
\fboxsep=1pt
\type{cltest}
\type{cl::one}
\type{foobar}
\type{foo_zero}
\const{a1234}
\const{a//test}
\word{helloworld}
\word{zoo}
\type{zoologist}
\printindex
\end{document}
.idx 文件的内容为:
\indexentry{\detokenize {cl}\detokenize {test}}{1}
\indexentry{\detokenize {cl::}!\detokenize {one}}{1}
\indexentry{\detokenize {foo}\detokenize {bar}}{1}
\indexentry{\detokenize {foo_}!\detokenize {zero}}{1}
\indexentry{\detokenize {a}\detokenize {1234}}{1}
\indexentry{\detokenize {a//}!\detokenize {test}}{1}
\indexentry{\detokenize {helloworld}}{1}
\indexentry{\detokenize {zoo}}{1}
\indexentry{\detokenize {zoo}!\detokenize {logist}}{1}
如果这个解决方案对您没有帮助,很抱歉...