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}
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}
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}
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.