Remove spaces from macro argument

Just another solution that works (apart from the one linked by campa):

\documentclass{article}
\usepackage{expl3,xparse}
\NewDocumentCommand{\backend}{m}{#1}
\ExplSyntaxOn
\NewDocumentCommand{\command}{m}{
    \tl_set:Nn \l_tmpa_tl {#1}
    \tl_replace_all:Nnn \l_tmpa_tl { ~ } { }
    \backend{\tl_use:N\l_tmpa_tl}
}
\ExplSyntaxOff
\begin{document}
\command{My space is useless!}
\end{document}

Update: As suggested in the comments now a version with expansion (and with correction of the typo [forgotten comma]).

\documentclass{article}
\usepackage{expl3,xparse}
\NewDocumentCommand{\backend}{m}{#1}
\ExplSyntaxOn
\NewDocumentCommand{\command}{m}{
    \tl_set:Nn \l_tmpa_tl {#1}
    \tl_replace_all:Nnn \l_tmpa_tl { ,~ } { , }
    \exp_args:No \backend { \l_tmpa_tl }
}
\ExplSyntaxOff

\def\foo{quack}

\begin{document}
\command{My space, is useless!, \foo}
\end{document}

Here's a version that can handle macros in the argument. For demonstration purposes, I make \backend perform a \detokenize on its argument, so that we can see exactly what tokens it receives. Note that, in the presented output, the space after \mymacro is a function of \detokenize and not of the \command macro.

As to the logic, the \readlist macro reads the comma separated list into an array \myarg. The * invocation of \readlist* discards empty space around each item in the list. Then, the \foreachitem loop goes through each item in sequence and I use \g@addto@maco to append the tokens of the item to \tmp, along with commas at the proper places. A once-expanded \tmp is finally passed to \backend.

The key point I will mention is that the original tokens are passed directly to \backend with this method. No further expansion of the argument is required by \backend to obtain the desired tokens. It is as if one typed the space-free argument list directly to \backend.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{listofitems}
\makeatletter
\newcommand\command[1]{%
  \setsepchar{,}%
  \readlist*\myarg{#1}%
  \def\tmp{}%
    \foreachitem\x\in\myarg{%
      \ifnum\xcnt=1\relax\else\g@addto@macro\tmp{,}\fi%
      \expandafter\g@addto@macro\expandafter\tmp\expandafter{\x}%
    }%
  \expandafter\backend\expandafter{\tmp}%
}
\makeatother
\newcommand\backend[1]{[\detokenize{#1}]}
\begin{document}
\command{a, b}

\command{a, b,c,  \mymacro, dfdg}
\end{document}

enter image description here

Note that, with the above code, only spaces around commas are discarded...whereas spaces within an argument are preserved, so that \command{a a , bb b, c} is processed as \backend{a a,bb b,c}. That may be a non-issue for the OP, if all arguments contain no spaces by their nature. Or it may even be a desired feature.

On the other hand, if it is desired to remove all spaces, including intra-argument spaces, then the following code will suffice. Here, it uses the space, rather than the comma, as the item-separator in digesting the list. Then, when it regurgitates the list item-by-item, the separator (space) is not part of the regurgitated list item.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{listofitems}
\makeatletter
\newcommand\command[1]{%
  \setsepchar{ }%
  \readlist\myarg{#1}%
  \def\tmp{}%
    \foreachitem\x\in\myarg{%
      \expandafter\g@addto@macro\expandafter\tmp\expandafter{\x}%
    }%
  \expandafter\backend\expandafter{\tmp}%
}
\makeatother
\newcommand\backend[1]{[\detokenize{#1}]}
\begin{document}
\command{a, b}

\command{a, b,c,  \mymacro, df dg}
\end{document}

This would remove all spaces around commas:

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\command}{m}
 {
  \seq_set_split:Nnn \l_jour_command_input_seq {,} { #1 }
  \exp_args:Nf \backend { \seq_use:Nn \l_jour_command_input_seq {,} }
 }
\seq_new:N \l_jour_command_input_seq
\ExplSyntaxOff

A test document

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\command}{m}
 {
  \seq_set_split:Nnn \l_jour_command_input_seq {,} { #1 }
  \exp_args:Nf \backend { \seq_use:Nn \l_jour_command_input_seq {,} }
 }
\seq_new:N \l_jour_command_input_seq
\ExplSyntaxOff

\newcommand{\backend}[1]{#1} % just for testing

\begin{document}

\command{a, b}

\command{a , b}

\command{a, ,b}

\end{document}

enter image description here

If you also want to remove empty items, use a clist:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\command}{m}
 {
  \clist_set:Nn \l_jour_command_input_clist { #1 }
  \exp_args:Nf \backend { \clist_use:Nn \l_jour_command_input_clist {,} }
 }
\clist_new:N \l_jour_command_input_clist
\ExplSyntaxOff

\newcommand{\backend}[1]{#1} % just for testing

\begin{document}

\command{a, b}

\command{a , b}

\command{a, ,b}

\end{document}

enter image description here

Explanation

We pass \backend the items of either the sequence or the clist, with , in between them. Both \seq_set_split:Nnn remove leading and trailing spaces from the items, storing the list in an “optimized form”. With \seq_use:Nn or \clist_use:Nn, the items are delivered “all at once” with the stated separator, when f-expanded. Hence the use of \exp_args:Nf, which sets aside the first token after it (\backend, in this case) and performs f-expansion to the contents of the braced group after it (the braces are left in place).

The main difference between \seq_set_split:Nnn and \clist_set:Nn is that the former honors empty items between two separator (that is, zero or one space), whereas the latter removes them.

Tags:

Macros