7

I want to define a macro that feeds its contents into a tikz \foreach statement, for example:

\newcommand\Macro[1]{ \foreach \x in {#1} {x=\x.} }

which is then used as \Macro{1,2,3,4}. Sometimes, I want to give it "empty" arguments, such as \Macro{,,,4,5,5}. I'd like to be able to detect the "empty" arguments and do something different in such cases. I thought that something like the following would work:

\newcommand\Macro[1]{%
  \foreach \x in {#1} {
    \if\relax\detokenize{\x}\relax Empty!
    \else x=\x.
    \fi 
  }
}

but for some reason this does not detect the empty arguments and instead produces:

enter image description here

I have tried many other things, such as expanding \x first, but I am yet to find anything that works.

Can any one see a way of doing this?

[My real code is generating a tikzpicture environment so I really want to use \foreach from `tikz.]

8

Something like this?

\documentclass{article}
\usepackage{tikz}
\newcommand\Macro[1]{%
  \foreach \x in {#1} {
    \ifx\x\empty\relax Empty!
    \else x=\x.
    \fi 
  }
}
\begin{document}
\Macro{,,,4,5,5}
\end{document}

enter image description here

  • Thanks marmot! I thought that I was probably being stupid and missing something obvious! – Andrew Feb 10 '18 at 3:50
9

The problem in the macro from the question:

\newcommand\Macro[1]{%
  \foreach \x in {#1} {
    \if\relax\detokenize{\x}\relax Empty!
    \else x=\x.
    \fi 
  }
}

is that \detokenize does not expand its argument and returns the two tokens \ and x. This is cured by adding an \expandafter:

\detokenize\expandafter{\x}

The full macro:

\newcommand\Macro[1]{%
  \foreach \x in {#1} {
    \if\relax\detokenize\expandafter{\x}\relax Empty!
    \else x=\x.
    \fi 
  }
}
5

The mandatory expl3 answer (after noting that \detokenize\expandafter{\x} would be the solution):

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\blankTF}{mmm}
 {% #1 = text to test, #2 = blank case, #3 = non blank case
  \str_if_eq_x:nnTF { #1 } { } { #2 } { #3 }
 }
\NewDocumentCommand{\lforeach}{O{,}mm}
 {% #1 = delimiter, #2 = list, #3 = code
  \seq_set_split:Nnn \l_andrew_foreach_seq { #1 } { #2 }
  \seq_map_inline:Nn \l_andrew_foreach_seq { #3 }
 }
\ExplSyntaxOff

\newcommand\Macro[1]{%
  \lforeach{#1}{%
    \blankTF{##1}{Empty!}{$|$##1$|$.}
  }
}

\begin{document}

\lforeach[-]{a-b--\texttt{c}}{%
    \blankTF{#1}{Empty!}{$|$#1$|$.}
  }

\lforeach{, ,,4, 5 ,5}{%
    \blankTF{#1}{Empty!}{$|$#1$|$.}
  }

\Macro{, ,,4, 5 ,5}

\end{document}

enter image description here

The current item in the cycle is denoted by #1 (which has to become ##1 in the definition of \Macro).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.