8

Is there a way to count the number of entries in an .idx file? Currently I'm using the following to accomplish the job but I'm wondering if there is an all TeX/LaTeX way to accomplish the same thing. Were there then I wouldn't have to fit a run of 'Count' into the build process. Here is the code:

#!/usr/bin/perl
# Count.pl -- generate index count info for tex
use strict;
use warnings;
use diagnostics;

our $VERSION = '0.04';

UpdateLines('names.tex',NLines($ARGV[0] . '.idx'));
UpdateLines('places.tex',NLines('places.idx'));

sub NLines {
    my $filename = shift;
    my @f;
    my $fh;

    open($fh, '<', $filename);
    @f = <$fh>;
    return scalar @f;
}

sub UpdateLines {
    my $filename = shift;
    my $lines = shift;
    my $fh;

    open($fh, '>', $filename);
    print $fh "There are $lines entries in this index.\n";
}

It occurs to me as I write this that since I use a collection of macros to index the various forms of names and places that I could add the necessary to increment the obvious counters inline so to speak. If anyone else has a better idea, jump on board. If not and if I manage to cobble something together then I'll post it as an answer in case someone else has this counting compulsion. OCD much?

8
  • You could redefine \index to add to a CSV the list of enteres that are indexed (if not already in the list), and then \AtEndDocument count the number of elements in this CSV. Mar 17, 2013 at 1:29
  • 6
    If all you want is the line count then (on *nix) wc -l is easier than the perl script (except that you've already written the perl script). Mar 17, 2013 at 1:31
  • What's the aim? Do you use xindy or makeindex? Mar 17, 2013 at 6:57
  • @MarcoDaniel Each index has a line that states There are n entries in this index. The Perl script was how I counted them simply by counting lines in the .idx file created by makeindex.
    – hsmyers
    Mar 17, 2013 at 9:17
  • 1
    @barbarabeeton Ah! You of course have Editor's Disease! As do I :) The answer is that precision is not a requirement here. Since this is a family history, the numbers are more of a guide than anything else. At the moment, the naive approach just counts lines in the .idx files. My new approach counts each instance of indexing. I'll have to give this some thought as to what would be best. Luckily the audience is un-critical :)
    – hsmyers
    Mar 17, 2013 at 12:18

3 Answers 3

3

You can change the \item command to increment a counter and then the \endtheindex command to show the counter value (and to reset the counter to zero for the next index):

\documentclass{book}
\usepackage{etoolbox}

\usepackage{imakeidx}
\makeindex[name=names,title=Index of Names]
\makeindex[name=places,title=Index of Places]

\makeatletter
% in the index, \item is \@idxitem
\appto{\@idxitem}{\stepcounter{itemcount}}
% Show the counter's value at the end and reset the counter
\appto{\endtheindex}{%
  \noindent\fbox{This index had \theitemcount~items}\par
  \setcounter{itemcount}{0}}

\newcounter{itemcount}
\makeatother

\begin{document}
\mainmatter
\chapter{A}
\index[names]{Euclid}
\index[places]{Alexandria}

\index[names]{Archimedes}
\index[places]{Syracuse}

\index[names]{Euler}
\index[places]{Basel}
\index[places]{Berlin}
\index[places]{St. Peterburg}

\index[names]{Newton}
\index[places]{Cambridge}


\backmatter

\printindex[names]
\printindex[places]

\end{document}

enter image description here

enter image description here

11
  • Nice! Some very useful internals here :) More Virtual Cake(TM) in the offing here :)
    – hsmyers
    Mar 17, 2013 at 10:46
  • @egreg -- this is nice and straightforward, but what if (as expressed in the original question) the number of entries should be the number of entries in the .idx file? what if one "final" entry has multiple page numbers? and what is actually wanted if an entry happens to be indexed twice on a single page, in which case the .idx file would have two entries, but the .ind file will have only one? Mar 17, 2013 at 12:04
  • @barbarabeeton In that case I would count the lines in the .idx file, rather than patching the \index command, probably with a Perl (or the preferred language) script. A TeX-only solution could be devised, but it would be rather slow.
    – egreg
    Mar 17, 2013 at 12:09
  • @barbarabeeton The original (1st edition) index had 5824 entries for names and was neither accurate nor complete. I'm significantly OCD when it comes to this such that I'll probably spend quite a bit of time figuring out what would be best.
    – hsmyers
    Mar 17, 2013 at 12:28
  • @egreg I have similar question as @barbara beeton : How to do the counting if there is only a subentry to the index e.g. \index[names]{Euler!childhood} so it would count childhood but not Euler if I don't have explicitly \index[names]{Euler}? Sep 15, 2016 at 9:21
3

An atempt to answer the original question. The number of entries in the .idx file is counted via \input command:

\documentclass[oneside]{book}
\usepackage{imakeidx}
\def\CountIndexOccurrences#1{%
\expandafter\newcount\csname #1\endcsname%
\expandafter\newcount\csname #1\endcsname%
\def\indexentry##1##2{\expandafter\advance\csname #1\endcsname 1}%
\IfFileExists{#1.idx}{\input{#1.idx}}{}%
}
\CountIndexOccurrences{names}
\CountIndexOccurrences{places}
\def\TotalBox#1{%
\fbox{There are \expandafter\the\csname #1\endcsname\ occurrences 
of items from this index}\par}
\makeindex[name=names,title=Index of Names]%
\makeindex[name=places,title=Index of Places]%
\begin{document}
\mainmatter
\chapter{A}
Euclid\index[names]{Euclid}
(Alexandria\index[places]{Alexandria})

Archimedes\index[names]{Archimedes}
(Syracuse\index[places]{Syracuse})

Newton\index[names]{Newton}
(Cambridge\index[places]{Cambridge})

\newpage
Newton\index[names]{Newton}
(Cambridge\index[places]{Cambridge})

Euler\index[names]{Euler}
(Basel\index[places]{Basel},
Berlin\index[places]{Berlin},
St. Peterburg\index[places]{St.~Peterburg})

Newton\index[names]{Newton}
(Cambridge\index[places]{Cambridge})

Euclid\index[names]{Euclid}
(Alexandria\index[places]{Alexandria})

\backmatter

\printindex[names]
\TotalBox{names}
\printindex[places]
\TotalBox{places}
\end{document}

Page 1 Page 2 Index of Names Index of Places

Content of the names.idx, 7 entries:

\indexentry{Euclid}{1}
\indexentry{Archimedes}{1}
\indexentry{Newton}{1}
\indexentry{Newton}{2}
\indexentry{Euler}{2}
\indexentry{Newton}{2}
\indexentry{Euclid}{2}

Content of the places.idx, 9 entries:

\indexentry{Alexandria}{1}
\indexentry{Syracuse}{1}
\indexentry{Cambridge}{1}
\indexentry{Cambridge}{2}
\indexentry{Basel}{2}
\indexentry{Berlin}{2}
\indexentry{St.~Peterburg}{2}
\indexentry{Cambridge}{2}
\indexentry{Alexandria}{2}
6
  • 1
    Is there an off by one error here or am I unable to count? Bear in mind that inability to count may be true regardless :)
    – hsmyers
    Mar 17, 2013 at 19:05
  • Why don't you put the code now in \CountIndexOccurrences inside \TotalBox? You won't even need a new counter, just use a temporary one such as \count255. Inputting the .idx file in the preamble or after \printindex takes the same time and, after \printindex the file will be there and closed, because imakeidx closes the .idx file in order to run MakeIndex.
    – egreg
    Mar 18, 2013 at 0:21
  • @hsmyers It's neither :) It's just different things were counted. It counts the number of \idexenrty in idx files, as was originally requested (see content of the names.idx and places.idx just added for convenience). A few entries were added to the MWE in order to address some of remarks (some of the entries on the same page).
    – g.kov
    Mar 18, 2013 at 0:28
  • @egreg: There's more than one way to skin a cat. Besides, when files are scanned in the preamble, the numbers can be used, say, in the Introduction.
    – g.kov
    Mar 18, 2013 at 0:38
  • @g.kov You could also write the result in the .aux file. ;-)
    – egreg
    Mar 18, 2013 at 0:40
1

As I said in the body of the question, here is the solution I came up with some 8 hours ago (would have posted then excepting my link to tex.stackexchange.com was down. That aside, here is my counter neutral code:

%%
%% Indexing Macros
%%
\newcounter{Names}
\newcounter{Places}
\newcommand{\incNames}{\addtocounter{Names}{1}}
\newcommand{\incPlaces}{\addtocounter{Places}{1}}
\newcommand\IA[3]{\incNames #1\index{#2!#3}}
\newcommand\IAA[3]{\incNames #1\index{#2 (#3)}}
\newcommand\IM[4]{\incNames #1\index{#2!#3, (#4.)}}
\newcommand\IS[1]{\incNames #1\index{#1 \ding{45}}}
\newcommand\PI[1]{\incPlaces #1\index[places]{#1 \ding{45}}}
\newcommand\PIA[2]{\incPlaces #1\index[places]{#1, (\SCA{#2})}}
\newcommand\PIAA[3]{\incPlaces #1\index[places]{#2, (\SCA{#3})}}
\newcommand\PO[3]{\incPlaces #1\index[places]{#1, (\SCA{#2})|{\emph{\small #3}}}}
\newcommand\SCA[1]{\textsc{\MakeLowercase{#1}}}

Starting at \IA, are the modified originals. This so blindingly obvious now that it is in place that it makes me question my problem solving abilities :( Clearly I need more practice in answers---questions are easy, need to get back to answers! As an aside, it is fun to see that this modification ups the self-documentation factor!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .