How to automatically place number of occurrences of a certain command inside xparse environment at every occurence of that command?

There is an (xparse) environment \myEnv, and there is unspecified number of \myCo commands provided by the user inside that environment. I need to write a code for the environment which would count the number of \myCo occurrences and would display that number at each \myCo occurrence.

\documentclass[varwidth]{standalone}

\usepackage{expl3}
\usepackage{xparse}

\def\myCo{}

\begin{document}
\ExplSyntaxOn
\NewDocumentEnvironment{myEnv}{+b}
{ #1 % before displaying the contents,
%  I need to count how many \myCo
%   occurrences there are and display this number
%    at each occurrence of \myCo
} {}
\ExplSyntaxOff
\begin{myEnv}
\myCo This is sentence 1. This is sentence 2.\myCo This is sentence 3.\myCo This is sentence 4. This is sentence 5. This is sentence 6.\myCo
\end{myEnv}
\end{document}


I would expect the output to look something like this: (4) This is sentence 1. This is sentence 2.(4) This is sentence 3.(4) This is sentence 4. This is sentence 5. This is sentence 6.(4)

where (4) is the number of \myCo commands.

• Do you have control over \myCo? If so, you could just put a counter inside the macro that counts its own invocations. – Henri Menke Jun 8 at 6:00
• Can myEnvs that contain \myCos be nested? How to treat, e.g., \begin{myEnv}\myCo ... \myCo ... \begin{myEnv}\myCo ... \myCo\end{myEnv}... \myCo...\end{myEnv} ? – Ulrich Diez Jun 8 at 14:04
• @HenriMenke That wouldn't quite work as the OP wants the total count rather than an incremental count. You could instead add a counter and at the end of the document save the counter to the aux file and then print the final total from the aux file using a \ref{...}erence. If you want the total count inside an environment that appears in different parts of the document then it is trickier to make this idea fly. – Andrew Jun 8 at 14:52

For both of these things you can use LaTeX3 regular expressions. To count the number of occurrences of \myCo you can use \regex_count:nnN and then you can use \regex_replace_all:nnN to insert the count after each instance of the command. The regular expression match for the control sequence \myCo is \c{myCo} so to find the number of occurrences you would use something like:

\regex_count:nnN {\c{myCo}} {#1} \l_tmpa_int


and the \regex_replace_all:nnN command is similar. With this in place the output produced by your MWE is the expected:

Here is the full code.

\documentclass[varwidth, border=10mm]{standalone}

\usepackage{expl3}
\usepackage{xparse}

\def\myCo{}

\begin{document}
\ExplSyntaxOn
\int_new:N \l_myCo_int
\tl_new:N \l_myenv_tl
\NewDocumentEnvironment{myEnv}{+b}
{
\regex_count:nnN {\c{myCo}} {#1} \l_myCo_int
\tl_set:Nn \l_myenv_tl {#1}
\regex_replace_all:nnN {\c{myCo}}
{\c{myCo}~(\c{int_use:N} \c{l_myCo_int})} \l_myenv_tl
\tl_use:N \l_myenv_tl
} {}
\ExplSyntaxOff
\begin{myEnv}
\myCo This is sentence 1. This is sentence 2.\myCo
This is sentence 3.\myCo This is sentence 4.
This is sentence 5. This is sentence 6.\myCo
\end{myEnv}
\end{document}


If your environment's contents doesn't contain counter advancing commands, you can simply typeset the contents in a discarded box, changing the meaning of \myCo inside the box.

\documentclass{article}

\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\myCo}{}
{
\__bp_myco:
}
\NewDocumentEnvironment{myEnv}{+b}
{
\int_zero:N \g__bp_myco_int
\vbox_set:Nn \l_tmpa_box
{
\cs_set:Nn \__bp_myco: { \int_gincr:N \g__bp_myco_int }
#1
}
#1
}{}

\int_new:N \g__bp_myco_int
\cs_new:Nn \__bp_myco:
{
(\int_to_arabic:n { \g__bp_myco_int })
}
\ExplSyntaxOff

\begin{document}

\begin{myEnv}
\myCo\ This is sentence 1.
This is sentence 2. \myCo\ This is sentence 3. \myCo\ This is sentence 4.
This is sentence 5. This is sentence 6.\myCo
\end{myEnv}

\end{document}


In case you need counting the single instances of \myCo separately for each instance and each nesting level of the myEnv environment, you can achieve that by defining myEnv and \myCo in a way where you have LaTeX both count instances of the myEnv-environment and count instances of the \myCo-macro and where a \label command for retrieving the value of the last \myCo is issued at the end of the myEnv environment.

If you have LaTeX count the \myCos in terms of \refstepcounter, you can place \label commands behind them for referencing.

I implemented things in a way where you can do with or without the hyperref package.

When loading hyperref, referencing without creation of a hyperlink is availabvle via \ref*.
But that "starred" referencing command is not available when doing without hyperref. Therefore I used the refcount package for implementing a referencing command without creation of a hyperlink.
This command will be available no matter if hyperref is loaded or is not loaded.

As internally \label..\ref/\getrefbykeydefault is used, you need to compile the example at least twice/until the warnings
LaTeX Warning: There were undefined references. and
LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right
do not occur in the console/in the log file any more .

\documentclass{article}

%\usepackage{hyperref}
\usepackage{refcount}
\usepackage{xspace}

\makeatletter
\IfRefUndefinedBabel{#1}{%
\refused{#1}%
\nfss@text {\reset@font \bfseries ??}%
}{%
\getrefbykeydefault{#1}{}{0}%
}%
}%

\newcounter{myEnvCtr}
\newcounter{myCoCtr}[myEnvCtr]
\def\theHmyEnvCtr{\arabic{myEnvCtr}}
\def\theHmyCoCtr{myEnvInstance\myEnv@THISmyEnvCtr.\arabic{myCoCtr}}
\def\themyCoCtr{\arabic{myCoCtr}}

\newcommand\myEnv@SAVEDcurrentlabel{}
\newcommand\myEnv@SAVEDcurrentHref{}
\newcommand\myEnv@SAVEDcurrentlabelname{}
\newcommand\myEnv@SAVEDmyCoCtr{}
\newcommand\myEnv@THISmyEnvCtr{0}

\newcommand\myCo{%
\refstepcounter{myCoCtr}%
% Save the referencing-data from the last \myCo:
\let\myEnv@SAVEDcurrentlabel=\@currentlabel
\let\myEnv@SAVEDcurrentHref=\@currentHref
\let\myEnv@SAVEDcurrentlabelname=\@currentlabelname
% In case of using zref-package or the like you may need
% to add the saving of the values of some more
% referencing-properties here.
}%
\newenvironment{myEnv}{%
\edef\myEnv@SAVEDmyCoCtr{\number\value{myCoCtr}}%
\stepcounter{myEnvCtr}%
\edef\myEnv@THISmyEnvCtr{\number\value{myEnvCtr}}%
}{%
\ifnum\number\value{myCoCtr}>0 %
\begingroup
% Restore the referencing-data from the last \myCo:
\let\@currentlabel=\myEnv@SAVEDcurrentlabel
\let\@currentHref=\myEnv@SAVEDcurrentHref
\let\@currentlabelname=\myEnv@SAVEDcurrentlabelname
% In case of using zref-package or the like you may need
% to add the restoring of the values of some more
% referencing-properties here.
\label{myEnvInstance.\myEnv@THISmyEnvCtr.LastmyCo}%
\endgroup
\fi
\setcounter{myCoCtr}{\myEnv@SAVEDmyCoCtr}%
}%

\makeatother

\begin{document}

\footnotesize

\begin{myEnv}
\myCo This is sentence 1. This is sentence 2.\myCo This is sentence 3.\myCo This is sentence 4. This is sentence 5. This is sentence 6.\myCo
\end{myEnv}

\bigskip

\bigskip

\noindent Now with nesting:

\bigskip

\begin{myEnv}
\noindent \verb|myEnv| -- nesting-level 0 -- nesting level 0 has \nolinkref{myEnv0last} \verb|\myCo|:\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 0's 1\textsuperscript{st} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 0's 2\textsuperscript{nd} \verb|\myCo|.\\

\begin{myEnv}
\noindent \verb|myEnv| -- nesting-level 1 -- nesting level 1 has \nolinkref{myEnv1last} \verb|\myCo|:\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 1's 1\textsuperscript{st} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 1's 2\textsuperscript{nd} \verb|\myCo|.\\

\begin{myEnv}
\noindent \verb|myEnv| -- nesting-level 2a -- nesting level 2a has \nolinkref{myEnv2alast} \verb|\myCo|:\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2a's 1\textsuperscript{st} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2a's 2\textsuperscript{nd} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2a's 3\textsuperscript{rd} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2a's 4\textsuperscript{th} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2a's 5\textsuperscript{th} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2a's 6\textsuperscript{th} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2a's 7\textsuperscript{th} \verb|\myCo|.\\
\myCo {}\label{myEnv2alast}%
$\leftarrow$This number in parentheses comes from myEnv's nesting level 2a's 8\textsuperscript{th} \verb|\myCo|.\\
\end{myEnv}

\noindent Back to \verb|myEnv| -- nesting-level 1 which has \nolinkref{myEnv1last} \verb|\myCo|:\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 1's 3\textsuperscript{rd} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 1's 4\textsuperscript{th} \verb|\myCo|.\\

\begin{myEnv}
\noindent \verb|myEnv| -- nesting-level 2b -- nesting level 2b has \nolinkref{myEnv2blast} \verb|\myCo|:\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2b's 1\textsuperscript{st} \verb|\myCo|.\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 2b's 2\textsuperscript{nd} \verb|\myCo|.\\
\myCo {}\label{myEnv2blast}%
$\leftarrow$This number in parentheses comes from myEnv's nesting level 2b's 3\textsuperscript{rd} \verb|\myCo|.\\
\end{myEnv}

\noindent Back to \verb|myEnv| -- nesting-level 1 which has \nolinkref{myEnv1last} \verb|\myCo|:\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 1's 5\textsuperscript{th} \verb|\myCo|.\\
\myCo {}\label{myEnv1last}%
$\leftarrow$This number in parentheses comes from myEnv's nesting level 1's 6\textsuperscript{th} \verb|\myCo|.\\
\end{myEnv}

\noindent Back to \verb|myEnv| -- nesting-level 0 which has \nolinkref{myEnv0last} \verb|\myCo|:\\
\myCo {}$\leftarrow$This number in parentheses comes from myEnv's nesting level 0's 3\textsuperscript{rd} \verb|\myCo|.\\
\myCo {}\label{myEnv0last}%
$\leftarrow$This number in parentheses comes from myEnv's nesting level 0's 4\textsuperscript{th} \verb|\myCo|.\\
\end{myEnv}

\end{document}