Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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?

share|improve this question
    
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. –  Peter Grill Mar 17 '13 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). –  Ethan Bolker Mar 17 '13 at 1:31
    
What's the aim? Do you use xindy or makeindex? –  Marco Daniel Mar 17 '13 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 '13 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 '13 at 12:18

3 Answers 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

share|improve this answer
    
Nice! Some very useful internals here :) More Virtual Cake(TM) in the offing here :) –  hsmyers Mar 17 '13 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? –  barbara beeton Mar 17 '13 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 '13 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 '13 at 12:28

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}
share|improve this answer
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 '13 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 '13 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 '13 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 '13 at 0:38
    
@g.kov You could also write the result in the .aux file. ;-) –  egreg Mar 18 '13 at 0:40

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!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.