# Count chars with xstring

I have the following code, which was provided by the xstring author Christian Tellechea, thank you very much. The idea is to count the number of character inside a structure that do belong to a predefined list.

\documentclass{article}
\usepackage{xstring}
\usepackage{blindtext}
\makeatletter
\def\countoccurs#1#2{%
\saveexpandmode\expandarg
%\exploregroups
\expandafter\def\expandafter\tmp@list\expandafter{\list,}%
\let\nboccur\z@
\loop
\unless\ifx\empty\tmp@list
\StrCut\tmp@list,\tmp@cs\tmp@list
%\StrCount{\noexpand#2}\tmp@cs[\tmp@cs]%
\StrCount{#2}\tmp@cs[\tmp@cs]%
\edef\nboccur{\number\numexpr\nboccur+\tmp@cs}%
\repeat
\restoreexpandmode
}
%\def\list{12,a,bc,9} % list can also be defined as this
\def\list{%
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,Q,r,s,t,u,v,w,x,y,z,%
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,S,X,Y,Z,%
1,2,3,4,5,6,7,8,9,0,%
}
\def\countenv#1{#1\countoccurs\list{#1}}
\makeatother

\begin{document}
\countenv{\begin{tabular}{ll} a & b \\ a & c \end{tabular}}\par
I counted: \nboccur.

\noindent\hrulefill

\countenv{\textbf{D}2345}\par
I counted: \nboccur.

\noindent\hrulefill

\countenv{\blindtext}\par
I counted: \nboccur.

\noindent\hrulefill

%\countoccurs\list{12987d bc abcabc999}
\countenv{12987d bc abcabc999}\par
I counted: \nboccur.

\noindent\hrulefill
\end{document}


As you can see in the output, the first and last counts are correct, but the others don't. I tried to use the \exploregroups and \noexpand#2 but luck with all presented examples. For example, the \noexpand#2 corrects the second output, but badly influences the first and third. Is there a away that works for all?

-
In my computer it compiles fine. – cacamailg Apr 10 '13 at 23:10
sorry had an older xstring.tex masking the tL2012 one, fixed now. – David Carlisle Apr 10 '13 at 23:20
Could you give an indication of why you want to do this (the macros are massively inefficient at this) to get a count for the whole document you can just use (say) latex followed by dvi2tty then wc (standard unix word count, which also counts characters) – David Carlisle Apr 10 '13 at 23:22
I wanted this just to count the number of characters in particular parts of the document. I was not aware that this could be highly inefficient with TeX in general. In fact, with after @egreg's answer I realized that for large documents it would take a lot of time. – cacamailg Apr 11 '13 at 0:06

\blindtext does not expand to some text, but executes many (unexpandable) commands before getting to a text.

You can try with kantlipsum, instead, which has the possibility of defining a macro expanding to one of its paragraphs.

\documentclass{article}
\usepackage{xstring}

\usepackage{kantlipsum}
\kantdef\mytext{1}

\makeatletter
\def\countoccurs#1#2{%
\saveexpandmode\expandarg
%\exploregroups
\expandafter\def\expandafter\tmp@list\expandafter{\list,}%
\let\nboccur\z@
\loop
\unless\ifx\empty\tmp@list
\StrCut\tmp@list,\tmp@cs\tmp@list
%\StrCount{\noexpand#2}\tmp@cs[\tmp@cs]%
\StrCount{#2}\tmp@cs[\tmp@cs]%
\edef\nboccur{\number\numexpr\nboccur+\tmp@cs}%
\repeat
\restoreexpandmode
}
%\def\list{12,a,bc,9} % list can also be defined as this
\def\list{%
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,Q,r,s,t,u,v,w,x,y,z,%
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,S,X,Y,Z,%
1,2,3,4,5,6,7,8,9,0,%
}
\def\countenv#1{#1\countoccurs\list{#1}}
\makeatother

\begin{document}
\countenv{\begin{tabular}{ll} a & b \\ a & c \end{tabular}}\par
I counted: \nboccur.

\noindent\hrulefill

\countenv{\textbf{D}2345}\par
I counted: \nboccur.

\noindent\hrulefill

\countenv{\mytext}\par
I counted: \nboccur.

\noindent\hrulefill

%\countoccurs\list{12987d bc abcabc999}
\countenv{12987d bc abcabc999}\par
I counted: \nboccur.

\noindent\hrulefill
\end{document}


After a long time (15 seconds on my machine, which is a very long processing time), you get this.

-
That does fix the third count, but not the second count. Any idea how to deal with macros like \textbf{} so that chars inside brackets are counted, but not the command itself? – cacamailg Apr 10 '13 at 23:08
@cacamailg If you go with \exploregroups you'll get wrong results in the first, because also tabular will get counted. – egreg Apr 10 '13 at 23:13
Yes. So no general solution is possible with TeX? – cacamailg Apr 10 '13 at 23:18
@cacamailg I'd answer with xii.tex – egreg Apr 10 '13 at 23:22
very nice comment :) – cacamailg Apr 11 '13 at 0:09