Skip to main content
added 199 characters in body
Source Link
Steven B. Segletes
  • 245.7k
  • 13
  • 350
  • 635

Here, I make space a catcode 12 before I absorb the argument. Then I count them using a \numexpr. But, as matexmatics noted, the result is not expandable, unless one changes the catcode of space in advance of the expansion, as in

{\catcode`\ =12 \edef\z{\countspaces{ A B C }}\z}

which yields the correct answer of 4. Here is the full MWE:

\documentclass{article}
\let\endcsp\empty
\makeatletter
\catcode`\_=10 %
\catcode`\ =12_%
\def\countspaces{\catcode`\ =12_\csp}%
\def\csp#1{\the\numexpr0\cspaux#1\endcsp\relax\catcode`\ =10_}%
\def\cspaux#1{\ifx#1\endcsp\else\ifx#1 +1\fi\expandafter\cspaux\fi}%
\catcode`\ =10_%
\catcode`\_=12 %
\makeatother
\begin{document}
\countspaces{ A B } Should return 3 (1 is ok too if leading and trailing spaces are removed)

\countspaces{A \mycommand B} Should return 2 (mycommand is not expanded)

\countspaces{A {a b c} B} Should return 2 (spaces inside groups are not counted)
\end{document}

enter image description here

Here, I make space a catcode 12 before I absorb the argument. Then I count them using a \numexpr. But, as matexmatics noted, the result is not expandable.

\documentclass{article}
\let\endcsp\empty
\makeatletter
\catcode`\_=10 %
\catcode`\ =12_%
\def\countspaces{\catcode`\ =12_\csp}%
\def\csp#1{\the\numexpr0\cspaux#1\endcsp\relax\catcode`\ =10_}%
\def\cspaux#1{\ifx#1\endcsp\else\ifx#1 +1\fi\expandafter\cspaux\fi}%
\catcode`\ =10_%
\catcode`\_=12 %
\makeatother
\begin{document}
\countspaces{ A B } Should return 3 (1 is ok too if leading and trailing spaces are removed)

\countspaces{A \mycommand B} Should return 2 (mycommand is not expanded)

\countspaces{A {a b c} B} Should return 2 (spaces inside groups are not counted)
\end{document}

enter image description here

Here, I make space a catcode 12 before I absorb the argument. Then I count them using a \numexpr. But, as matexmatics noted, the result is not expandable, unless one changes the catcode of space in advance of the expansion, as in

{\catcode`\ =12 \edef\z{\countspaces{ A B C }}\z}

which yields the correct answer of 4. Here is the full MWE:

\documentclass{article}
\let\endcsp\empty
\makeatletter
\catcode`\_=10 %
\catcode`\ =12_%
\def\countspaces{\catcode`\ =12_\csp}%
\def\csp#1{\the\numexpr0\cspaux#1\endcsp\relax\catcode`\ =10_}%
\def\cspaux#1{\ifx#1\endcsp\else\ifx#1 +1\fi\expandafter\cspaux\fi}%
\catcode`\ =10_%
\catcode`\_=12 %
\makeatother
\begin{document}
\countspaces{ A B } Should return 3 (1 is ok too if leading and trailing spaces are removed)

\countspaces{A \mycommand B} Should return 2 (mycommand is not expanded)

\countspaces{A {a b c} B} Should return 2 (spaces inside groups are not counted)
\end{document}

enter image description here

added 14 characters in body
Source Link
Steven B. Segletes
  • 245.7k
  • 13
  • 350
  • 635

Here, I make space a catcode 12 before I absorb the argument. Then I count them using a \numexpr. But, as matexmatics noted, the result is not expandable.

\documentclass{article}
\newcounter{mycount}
\let\endcsp\relax\let\endcsp\empty
\makeatletter
\catcode`\_=10%\catcode`\_=10 %
\catcode`\ =12%=12_%
\def\countspaces{\setcounter{mycount}{0}\catcode`\ =12_\csp}%
\def\csp#1{\cspaux#1\endcsp\catcode`\\the\numexpr0\cspaux#1\endcsp\relax\catcode`\ =10_}%
\def\cspaux#1{\ifx#1\endcsp\themycount\else%
__\ifx#1\ifx#1\endcsp\else\ifx#1 \stepcounter{mycount}\fi\expandafter\cspaux\fi+1\fi\expandafter\cspaux\fi}%
\catcode`\_=12%
\catcode`\ =10%=10_%
\catcode`\_=12 %
\makeatother
\begin{document}
\countspaces{ A B } Should return 3 (1 is ok too if leading and trailing spaces are removed)

\countspaces{A \mycommand B} Should return 2 (mycommand is not expanded)

\countspaces{A {a b c} B} Should return 2 (spaces inside groups are not counted)
\end{document}

enter image description here

Here, I make space a catcode 12 before I absorb the argument. Then I count them.

\documentclass{article}
\newcounter{mycount}
\let\endcsp\relax
\makeatletter
\catcode`\_=10%
\catcode`\ =12%
\def\countspaces{\setcounter{mycount}{0}\catcode`\ =12_\csp}%
\def\csp#1{\cspaux#1\endcsp\catcode`\ =10_}%
\def\cspaux#1{\ifx#1\endcsp\themycount\else%
__\ifx#1 \stepcounter{mycount}\fi\expandafter\cspaux\fi}%
\catcode`\_=12%
\catcode`\ =10%
\makeatother
\begin{document}
\countspaces{ A B } Should return 3 (1 is ok too if leading and trailing spaces are removed)

\countspaces{A \mycommand B} Should return 2 (mycommand is not expanded)

\countspaces{A {a b c} B} Should return 2 (spaces inside groups are not counted)
\end{document}

enter image description here

Here, I make space a catcode 12 before I absorb the argument. Then I count them using a \numexpr. But, as matexmatics noted, the result is not expandable.

\documentclass{article}
\let\endcsp\empty
\makeatletter
\catcode`\_=10 %
\catcode`\ =12_%
\def\countspaces{\catcode`\ =12_\csp}%
\def\csp#1{\the\numexpr0\cspaux#1\endcsp\relax\catcode`\ =10_}%
\def\cspaux#1{\ifx#1\endcsp\else\ifx#1 +1\fi\expandafter\cspaux\fi}%
\catcode`\ =10_%
\catcode`\_=12 %
\makeatother
\begin{document}
\countspaces{ A B } Should return 3 (1 is ok too if leading and trailing spaces are removed)

\countspaces{A \mycommand B} Should return 2 (mycommand is not expanded)

\countspaces{A {a b c} B} Should return 2 (spaces inside groups are not counted)
\end{document}

enter image description here

Source Link
Steven B. Segletes
  • 245.7k
  • 13
  • 350
  • 635

Here, I make space a catcode 12 before I absorb the argument. Then I count them.

\documentclass{article}
\newcounter{mycount}
\let\endcsp\relax
\makeatletter
\catcode`\_=10%
\catcode`\ =12%
\def\countspaces{\setcounter{mycount}{0}\catcode`\ =12_\csp}%
\def\csp#1{\cspaux#1\endcsp\catcode`\ =10_}%
\def\cspaux#1{\ifx#1\endcsp\themycount\else%
__\ifx#1 \stepcounter{mycount}\fi\expandafter\cspaux\fi}%
\catcode`\_=12%
\catcode`\ =10%
\makeatother
\begin{document}
\countspaces{ A B } Should return 3 (1 is ok too if leading and trailing spaces are removed)

\countspaces{A \mycommand B} Should return 2 (mycommand is not expanded)

\countspaces{A {a b c} B} Should return 2 (spaces inside groups are not counted)
\end{document}

enter image description here