The optional argument of \fun is to hold a comma-separated list of
elements that are to be "exploded".
With your code, there is always trailing empty element.
That trailing element is also processed by the \@for-loop.
Therefore the output is always
1:a-2:b, 1:c-2:d, 1:e-2:f, 1:g-2:, 1:-2:,
ìnstead of:
1:a-2:b, 1:c-2:d, 1:e-2:f, 1:g-2:,
Below is a suggestion where both blank elements and empty elements
within the optional argument's list are cranked out.
Ulrich
\documentclass{minimal}
\makeatletter
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that
%% argument which is to be checked is empty>}%
%% {<Tokens to be delivered in case that
%% argument which is to be checked is not empty>}%
\newcommand\@CheckWhetherNull[1]{%
\expandafter\@secondoftwo\string{\expandafter\@secondoftwo
\expandafter{\expandafter{\string#1}\expandafter\@secondoftwo
\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@firstoftwo\expandafter\@secondoftwo\expandafter}\string
}\@firstoftwo
}%
%%----------------------------------------------------------------------
%% Check whether arg contains no @ of catcode 11 (letter) on top brace
%% level
%%......................................................................
%% \CheckWhetherNoLetterAt{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument which is
%% to be checked does not contain @ of catcode 11>}%
%% {<Tokens to be delivered in case that argument which is
%% to be checked does contain @ of catcode 11>}%
\newcommand\@RemoveToLetterAt{}%
\long\def\@RemoveToLetterAt#1@{}%
\newcommand\@CheckWhetherNoLetterAt[1]{%
\expandafter\@CheckWhetherNull
\expandafter{\@RemoveToLetterAt#1@}%
}%
%%----------------------------------------------------------------------
%% \fun, \explode etc:
%%......................................................................
\newcommand{\fun}[1][a@b,c@d,e@f,g,]{%%%
\@for\elem:=#1\do{%
\expandafter\expandafter\expandafter\@CheckWhetherNull
\expandafter\expandafter\expandafter{%
\expandafter\@firstoftwo\elem{}.}{}{%
\explode{\elem}1:\@pOne-2:\@pTwo, %
}%
}%
}
\begingroup
\lccode`\!=`\@% Catcode of ! is 12 (other).
% Lowercasing ! now yields @ of catcode 12 (other).
\lowercase{%
\endgroup
\newcommand\@AtLetterExplode{}%
\def\@AtLetterExplode#1@#2@#3\@nil{\edef\@pOne{#1}\edef\@pTwo{#2}}%
\newcommand\@AtOtherExplode{}%
\def\@AtOtherExplode#1!#2!#3\@nil{\edef\@pOne{#1}\edef\@pTwo{#2}}%
\newcommand\explode[1]{%
\expandafter\@CheckWhetherNoLetterAt\expandafter{#1}%
{\expandafter\@AtOtherExplode#1!!}%
{\expandafter\@AtLetterExplode#1@@}%
\@nil
}%
}%
\makeatother
\begin{document}
\fun
\makeatletter
\fun[a@b,, ,c@d,e@f,g, ]
\fun[a@b,, ,c@d,e@f,g,]
\fun[a@b,c@d,e@f,g, ]
\fun[a@b,c@d,e@f,g]
\makeatother
\fun[a@b,, ,c@d,e@f,g, ]
\fun[a@b,, ,c@d,e@f,g,]
\fun[a@b,c@d,e@f,g, ]
\fun[a@b,c@d,e@f,g]
\end{document}
@character is a special LaTeX character. Within style files, it is interpreted as an alphabetical character. Within documents, it is interpreted as a symbol. If you place\makeatletterin your document (not recommended except for debugging and emulating style-file syntax), the second case works properly. – Steven B. Segletes May 16 '16 at 11:46\makeatletteraware place and you just defined\@explodeto separate the arguments in letter-@and when using in the document you are using other-@. – Manuel May 16 '16 at 11:47