带有条件和文本识别的自定义索引宏

带有条件和文本识别的自定义索引宏

我无法自己解决这个问题,也无法通过搜索这个很棒的网站来解决这个问题。问题在于索引。我仍然认为自己是 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::Sourcecl::Program、 或CL_xxxCL_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!

所以我有一个相当普遍的问题

  1. 如何定义一个宏,该宏可以索引具有给定起始字符的任何单词,并将该起始字符与其余部分分开以进行两级索引?我的意思是以下内容: \type{cl::Type}将产生类似的效果\texttt{cl::Type}\index{cl::!Type}。最好是宏默认cl::与其余部分分开,并且应该像平常一样对任何其他单词起作用。

  2. 如何为不同类型的使用制作这样的宏?我宁愿避免为、、、、等输入所有非常相似的宏\kword-\var它们都非常相似,只是排版不同。也许这是一种编写类似宏来生成另一个宏的方法\const\type\func

  3. 理想的解决方案将允许使用一些预定义的前缀来索引单词,例如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}

如果这个解决方案对您没有帮助,很抱歉...

相关内容