New version taking into account the comments of jps
and egreg.
The code below counts the spaces. For example, A {a b c} B is interpreted as 0+1+0*(0+1+1)+1 and then evaluated with \int_eval:n as 2.
There is an optional star for the command \countspaces. It allows to decide case by case whether commands such as \space, \,, \ , \@sptoken or \! should be taken into account.
\documentclass[border=6pt]{standalone}
\usepackage{tabularray}
\usepackage{xcolor}
\usepackage{fvextra}
\ExplSyntaxOn
\cs_new:Npn \__Vincent_count_spaces_aux_i:n #1
{
\str_case:ne {#1}
{
{ ~ } { + 1 }
{ \c_left_brace_str } { + 0 * ( 0 }
{ \c_right_brace_str } { ) }
}
}
\makeatletter
\cs_new:Npn \__Vincent_count_spaces_aux_ii:nn #1#2
{
\tl_if_single_token:nT {#2}
{
\token_if_control_word:NT #2 { - 1 }
\IfBooleanT {#1}
{
\token_case_meaning:NnT #2
{
\space {}
\, {}
% \ {}%choose whether \ should be counted twice
\ { - 1 }%choose whether \ should be counted twice
\@sptoken {}
\! {}
}
{ + 1 }
}
}
}
\makeatother
\NewExpandableDocumentCommand \countspaces { s m }
{
\int_eval:n
{
0
\str_map_function:nN {#2} \__Vincent_count_spaces_aux_i:n
\tl_map_tokens:nn {#2} { \__Vincent_count_spaces_aux_ii:nn {#1} }
}
}
\ExplSyntaxOff
\newcommand{\test}[1]{\Verb*{#1} & \edef\testA{\countspaces{#1}}\testA & \edef\testB{\countspaces*{#1}}\testB\\}
\begin{document}
\begin{tblr}[expand=\test]{
colspec=lcc,
hline{2}=1pt,
row{odd}=lightgray,
row{1}=gray
}
input & \Verb{\countspaces} & \Verb{\countspaces*}\\
\test{ A B }% Should return 3 (1 is ok too if leading and trailing spaces are removed)
\test{A \mycommand B}% Should return 2 (\mycommand is not expanded)
\test{A {a b c} B}% Should return 2 (spaces inside groups are not counted)
\test{a}
\test{\,}
\test{\@}
\test{\ }
\test{\@ a}
\test{ \,a}
\test{ C { k l {m n } } X Y }
\test{\x\y}
\test{ A \space B \, C \ D}
\test{ A \space B \, C \ D { \space} \! E }
\end{tblr}
\end{document}

{A \mycommand B}will only return1, because the "space" after\mycommandis a terminator to the name, not a cat-10 space.\@sptoken) to be handled? As a space, or not?