0

I want to expand a macro argument into a string, remove all the spaces, then append and prepend the string inside a \NewDocumentCommand macro definition.

Here's my MWE using LuaLaTeX.

enter image description here

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack}
\usepackage{mathtools, amssymb}
\usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math}
    \setmathfont{Latin Modern Math}
\usepackage{xparse}
\usepackage{xpatch}

    % \ExpandArg (https://tex.stackexchange.com/a/515425)
\ExplSyntaxOn
\cs_new_protected:Nn \__user_expand_arg:n
 {
  \tl_set:No \ProcessedArgument { #1 }
 }
\cs_set_eq:NN \ExpandArg \__user_expand_arg:n
\ExplSyntaxOff

    % \RemoveSpaces (https://tex.stackexchange.com/a/87510)
\makeatletter
\def\RemoveSpaces#1{\zap@space#1 \@empty}
\makeatother

    % \foo, \foobar, and \xy
\NewDocumentCommand{\foo}{>{\ExpandArg} m}{%
    \renewcommand{\foobar}{+\RemoveSpaces{#1}.}
    \xpatchcmd{\foobar}{+x-y.}{++xx--yy..}{}{} % check if there's a '+x-y.' w/o any spaces, then replace it with '++xx--yy..'
    \foobar % print the output
}
\newcommand{\foobar}{}
\newcommand{\xy}{ x - y }

\begin{document}\KOMAoptions{DIV=current}\Large%
    \[\foo{\xy}\] % if all the spaces are removed, it should print the output as '++xx--yy..' and not '+x-y.'
\end{document}

Why does this not work? I think the problem might be that I don't really understand how \RemoveSpaces works.

Thank you.

1 Answer 1

3

\zap@space works by full expansion, so has to be used inside of an \edef or \expanded context. Your \foobar's content will not be expanded inside of \renewcommand, so it will be exactly what you fill in there. The macro \xy is expanded once, leaving ␣x␣-␣y␣, and then you assign that to \foobar, which will contain +\RemoveSpaces{␣x␣-␣y␣}. now, which doesn't match your search string +x-y..

Notice however that \zap@space has several historic limitations: It has to be used inside of a full-expansion context, and it might remove braces you want to keep.

The following defines an argument processor that zaps all spaces without such limitations, and hence you can simply use #1 inside your \renewcommand.

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack}
\usepackage{xparse}
\usepackage{xpatch}

    % \ExpandArg (https://tex.stackexchange.com/a/515425)
\ExplSyntaxOn
\cs_new_protected:Nn \__user_expand_arg:n
 {
  \tl_set:No \ProcessedArgument { #1 }
 }
\cs_set_eq:NN \ExpandArg \__user_expand_arg:n
\cs_new_protected:Npn \__user_arg_zap_spaces:n #1
  {
    \tl_set:Nn \ProcessedArgument {#1}
    \tl_remove_all:Nn \ProcessedArgument { ~ }
  }
\cs_set_eq:NN \ArgZapSpaces \__user_arg_zap_spaces:n
\ExplSyntaxOff

    % \foo, \foobar, and \xy
\NewDocumentCommand{\foo}{>{\ArgZapSpaces}>{\ExpandArg} m}{%
    \renewcommand{\foobar}{+#1.}
    \xpatchcmd{\foobar}{+x-y.}{++xx--yy..}{}{} % check if there's a '+x-y.' w/o any spaces, then replace it with '++xx--yy..'
    \foobar % print the output
}
\newcommand{\foobar}{}
\newcommand{\xy}{ x - y }

\begin{document}\KOMAoptions{DIV=current}\Large%
    \[\foo{\xy}\] % if all the spaces are removed, it should print the output as '++xx--yy..' and not '+x-y.'
\end{document}

enter image description here


Just for completeness, this is how \zap@space works:

\zap@space is defined as

\def\zap@space#1 #2{#1\ifx#2\@empty\else\expandafter\zap@space\fi#2}

So it reads everything up to a space as #1, and outputs this. Additionally it reads one token (or braced group, which would be unbraced by this) and compares that to \@empty (which is the end marker in your \RemoveSpaces). If #2 isn't \@empty \zap@space calls itself. #2 is reinserted at the end (and if it's \@empty will expand to nothing so doesn't hurt). The approach taken can only work in full expansion, as #1 is always put before the next call to \zap@space, so we can't expand from the left until \zap@space is done (except in the nonsensical case that #1 only expands to nothing).

1
  • I see, thank you very much for your answer. Commented Aug 3, 2022 at 7:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .