62

I have a mathematical transformation that takes 16 parameters (grouped into 3+8+5) and would like to make a latex command for it, so that I can easily change the notation for it if the need arises.

As far as I know, both \def and \newcommand take a maximum of 9 arguments, is there any (recommended) way to extend this?

  • 3
    Perhaps you might show us the detail of what is wanted. This sounds like a question where the best answer will be to think carefully about the input you really require. – Joseph Wright Aug 21 '10 at 6:43
  • I edited the question to make it clear the parameters are not programmatic, but rather, an unavoidable part of the the maths that I'm using. – Simon Aug 21 '10 at 7:02
  • 1
    I wonder if there's a magic solution involving Currying. – Seamus Feb 21 '13 at 16:19
46

You are going to have to parse the arguments some at a time and store them into temporary registers or macros. For example

\newcommand\foo[9]{%
    \def\tempa{#1}%
    \def\tempb{#2}%
    \def\tempc{#3}%
    \def\tempd{#4}%
    \def\tempe{#5}%
    \def\tempf{#6}%
    \def\tempg{#7}%
    \def\temph{#8}%
    \def\tempi{#9}%
    \foocontinued
}
\newcommand\foocontinued[7]{%
    % Do whatever you want with your 9+7 arguments here.
}
  • Thanks TH - that's the same solution as supplied in the "black TeX magic" link provided by mindcorrosive. I think that I'll use the xargs package, since it will make my code clearer and I like the simple default arguments. – Simon Aug 21 '10 at 6:55
  • 4
    Can you give an example of how to declare and access/use the variables? – 7heViking Oct 15 '15 at 15:10
  • I ask the same question as @FireFly3000 . I did as you said above and called the two functions as follows: \pointscolors{100}{red}; \myarc{0}{0}{0}{0}{3}{2.645751311064591}{0}{-3}{2.645751311064591}; (sorry, I do not know how to format this), with 2 arguments and the next with 9 arguments. then I get this error: Argument of \myarc has an extra }. <inserted text> \par l.90 ...myarc{0}{0}{0}{0}{3}{2.645751311064591}{0} {-3}{2.645751311064591}; ? – Herman Jaramillo Nov 2 '15 at 23:01
  • 1
    I removed the "\foocontinued" from the first block (named "\foo") and my error disappeared. I think that line is in error because is called without parameters. – Herman Jaramillo Nov 2 '15 at 23:32
  • Within the definition-text of \foocontinued you can use the macros \tempa..\tempi and the arguments #1..#7, so within the definition-text of \foocontinued the first nine arguments are addressable via macro-calls and the following seven nine arguments are addressable via #<digit>-syntax. – Ulrich Diez Oct 21 '18 at 17:47
30

There's the xargs package, and there's also some black TeX magic. As for myself, being conditioned in Python, I prefer the key-value parameter syntax provided by keyval/xkeyval packages.

On an unrelated note, if I find myself needing more than 9 parameters, that usually means that my macro/def/code organization is not very good, and I'd try to improve that first. But of course, there are legitimate situations where 9 parameters are perfectly okay --- especially if you try to build a definition with a lot of knobs and tweaks.

  • Thanks, I don't know how my googling did not turn up the first option you gave. The 16 parameters define a nonlinear transformation - they're not options in the macro. – Simon Aug 21 '10 at 6:51
  • 3
    Actually, xargs does not allow more than 9 arguments - it only gives a neat interface for optional arguments. I'll have to use the TeX hack. – Simon Aug 21 '10 at 7:10
  • 3
    That's correct. Until you clarified what you need so much parameters for, I assumed it's for a macro, and you'd use the keyval interface. But of course in that case it's better with plain TeX. – Martin Tapankov Aug 21 '10 at 7:15
  • Actually you made me reconsider if I needed all those arguments and I ended up with 6 arguments in stead of 10 :) – 7heViking Oct 15 '15 at 16:05
21

NEW ANSWER

The listofitems package used here is preferable to my original answers below, because \readlist does not expand the argument when capturing it, nor does it rely on inconvenient roman-numeral syntax.

\documentclass{article}
\usepackage{listofitems}
\begin{document}
\setsepchar{ }
\readlist\arg{1 2 3 4 5 6 7 8 9 10 11 12 FinalArgument}
There are \arglen{} arguments.  The thirteenth is \arg[13]
\end{document}

ORIGINAL ANSWER

In a response to How to use variables inside a command when generating a table? I mention how the stringstrings package has a \getargs command that will parse large numbers of arguments that are passed within a single { }. To recap that reply,

\documentclass{article}
\usepackage{stringstrings}
\begin{document}
\getargs{1 2 3 4 5 6 7 8 9 10 11 12 FinalArgument}
There are \narg~arguments.  The thirteenth is \argxiii
\end{document}

The result to this example is:

There are 13 arguments. The thirteenth is FinalArgument


EDIT: A much more efficient version of \getargs is available in the readarray package and called \getargsC (in deference to David Carlisle's help). Thus, the same task can be accomplished more quickly with

\documentclass{article}
\usepackage{readarray}
\begin{document}
\getargsC{1 2 3 4 5 6 7 8 9 10 11 12 FinalArgument}
There are \narg~arguments.  The thirteenth is \argxiii
\end{document}
  • Could you please edit your answer to show how these techniques can be used to define a command taking several arguments? – Psychonaut Feb 9 '17 at 14:03
  • @Psychonaut when you say several arguments, do you mean several arguments within a single set of braces? For example, the listofitems answer at the end of this answer: tex.stackexchange.com/questions/348366/… – Steven B. Segletes Feb 9 '17 at 14:44
  • 1
    It's also worth mentioning that the stringstrings package has some unwanted side effects due to definitions of \t et al, that are commonly used by latex users as shortcuts. BTW, the readarray package doesn't do that and seems a better alternative. – Geoff Pointer Aug 11 '17 at 1:11
10

Since it's a different technique, I also present the following: local macro definitions.

\documentclass{article}

\def\NineteenArgs#1#2#3#4#5#6#7#8#9{%
    \def\ArgsTenAndFurther##1##2##3##4##5##6##7##8##9{%
        \def\ArgNineteen####1{%
            ####1##9##8##7##6##5##4##3##2##1#9#8#7#6#5#4#3#2#1%
        }%
        \ArgNineteen%
    }%
    \ArgsTenAndFurther%
}

\begin{document}
                 %1234567890123456789
    \NineteenArgs abcdefghijklmnopqrs
\end{document}
  • 1
    This is beautiful, in a horrifying sort of way. I wanted \matr 1110 1110 1110 0000, and \newcommand{\matr}[9]{\def\matrMore##1##2##3##4##5##6##7{\begin{bmatrix}#1&#2&#3&#4\\#5&#6&#7&#8\\#9&##1&##2&##3\\##4&##5&##6&##7\end{bmatrix}}\matrMore} did the trick perfectly! – Radon Rosborough Mar 26 '17 at 2:03
  • Glad it helped. I trust you like the transparency of the argument naming scheme:-) – user10274 Mar 26 '17 at 15:25
1

This assumes no argument of a weird command contains a weird command. Here for “weird command” I mean one defined with the proposed \NewWeirdCommand below.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\NewWeirdCommand}{mmm}
 {% #1 = command to define, #2 = number of arguments, #3 = replacement text
  \cs_new:Npn #1
   {
    \tl_set:Nn \l__simon_parse_args_tl { #3 }
    \__simon_parse_args:n { #2 }
   }
 }
\NewDocumentCommand{\Arg}{m}
 {
  \seq_item:Nn \l__simon_parse_args_seq { #1 }
 }

\tl_new:N \l__simon_parse_args_tl
\seq_new:N \l__simon_parse_args_seq
\int_new:N \l__simon_parse_args_int

\cs_new_protected:Nn \__simon_parse_args:n
 {
  \seq_clear:N \l__simon_parse_args_seq
  \int_zero:N \l__simon_parse_args_int
  \__simon_parse_arg:n { #1 }
 }
\cs_new_protected:Nn \__simon_parse_arg:n
 {
  \int_incr:N \l__simon_parse_args_int
  \int_compare:nNnTF { \l__simon_parse_args_int } > { #1 }
   {
    \tl_use:N \l__simon_parse_args_tl
   }
   {
    \__simon_parse_arg_aux:nn { #1 }
   }
 }
\cs_new_protected:Nn \__simon_parse_arg_aux:nn
 {
  \seq_put_right:Nn \l__simon_parse_args_seq { #2 }
  \__simon_parse_arg:n { #1 }
 }
\ExplSyntaxOff

\begin{document}

\NewWeirdCommand{\foo}{4}{\Arg{1}-\Arg{2}-\Arg{3}-\Arg{4}END}
\NewWeirdCommand{\baz}{16}{%
  \Arg{16}-%
  \Arg{15}-%
  \Arg{14}-%
  \Arg{13}-%
  \Arg{12}-%
  \Arg{11}-%
  \Arg{10}-%
  \Arg{9}-%
  \Arg{8}-%
  \Arg{7}-%
  \Arg{6}-%
  \Arg{5}-%
  \Arg{4}-%
  \Arg{3}-%
  \Arg{2}-%
  \Arg{1}-%
  END%
}

\foo{a}{b}{c}{d}XXXX

\baz{a1}{b1}{c1}{d1}{a2}{b2}{c2}{d2}{a3}{b3}{c3}{d3}{a4}{b4}{c4}{d4}XXXX

\end{document}

In the replacement text, \Arg{<number>} denotes the corresponding collected argument.

No check is done, so if you define a weird command to have 15 arguments, \Arg{16} in the replacement text will output nothing.

enter image description here

If you are willing to use a slightly different syntax, with all arguments in an additional pair of braces, it's simpler:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\NewWeirdCommand}{mm}
 {% #1 = command to define, #2 = replacement text
  \cs_new:Npn #1 ##1
   {
    \tl_set:Nn \l__simon_args_tl { ##1 }
    #2
   }
 }
\NewDocumentCommand{\Arg}{m}
 {
  \tl_item:Nn \l__simon_args_tl { #1 }
 }

\tl_new:N \l__simon_parse_args_tl
\ExplSyntaxOff

\begin{document}

\NewWeirdCommand{\foo}{\Arg{1}-\Arg{2}-\Arg{3}-\Arg{4}END}
\NewWeirdCommand{\baz}{%
  \Arg{16}-%
  \Arg{15}-%
  \Arg{14}-%
  \Arg{13}-%
  \Arg{12}-%
  \Arg{11}-%
  \Arg{10}-%
  \Arg{9}-%
  \Arg{8}-%
  \Arg{7}-%
  \Arg{6}-%
  \Arg{5}-%
  \Arg{4}-%
  \Arg{3}-%
  \Arg{2}-%
  \Arg{1}-%
  END%
}

\foo{{a}{b}{c}{d}}XXXX

\baz{{a1}{b1}{c1}{d1}{a2}{b2}{c2}{d2}{a3}{b3}{c3}{d3}{a4}{b4}{c4}{d4}}XXXX

\end{document}
  • Hehe, the weird command. I like it. :P – manooooh Oct 22 '18 at 0:19
0

I was having the same error as @Herman-Jaramillo, so here is my correction of @TH's answer:

\newcommand\foo[9]{%
    \def\tempa{#1}%
    \def\tempb{#2}%
    \def\tempc{#3}%
    \def\tempd{#4}%
    \def\tempe{#5}%
    \def\tempf{#6}%
    \def\tempg{#7}%
    \def\temph{#8}%
    \foocontinued#9
}
\newcommand\foocontinued[7]{%
    % Do whatever you want with your 8+7 arguments here.
}

Then later:

\foo{1}{2}{3}{4}{5}{6}{7}{8}{{9}{10}{11}{12}{13}{14}{15}}

Notice that 9 through 15 are themselves in brackets. This solution is not perfect, since you cannot use 15 sets of brackets next to each other as cleanly as one might desire, but it worked for me.

  • Do: \newcommand\foo[9]{\def\tempa{#1}\def\tempb{#2}\def\tempc{#3}\def\tempd{#4}\def\tempe{#5}\def\tempf{#6}\def\tempg{#7}\def\temph{#8}\def\tempi{#9}\foocontinued} and \newcommand\foocontinued[7]{Arg1: \tempa\\Arg2: \tempb\\Arg3: \tempc\\Arg4: \tempd\\Arg5: \tempe\\Arg6: \tempf\\Arg7: \tempg\\Arg8: \temph\\Arg9: \tempi\\Arg10: #1\\Arg11: #2\\Arg12: #3\\Arg13: #4\\Arg14: #5\\Arg15: #6\\Arg16: #7} – Ulrich Diez Oct 21 '18 at 17:58
0

I can offer a macro \KeepKthOfLArguments which picks the K-th undelimited argument of a sequence of L undelimited arguments.

When doing macro-programming, you can pass the sequence of L undelimited arguments via a single undelimited macro argument.

I don't recommend using this for macros at user-level.

At user-level I recommend interfaces with keyval-syntax.

But sometimes I use such things with macros that both generate and process large lists of undelimited arguments automatically without the need of the user passing/typing these arguments.

\documentclass{article}

\makeatletter
%% Code for \KeepKthOfLArguments: 
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@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>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%=============================================================================
%% Keep only the K-th of L consecutive undelimited arguments.
%%   ( IF K < 1 OR K > L just remove L consecutive undelimited arguments. )
%%=============================================================================
%% \KeepKthOfLArguments{<integer number K>}%
%%                     {<integer number L>}%
%%                     <sequence of L consecutive undelimited arguments>
%%
%% If L < 1 yields nothing.
%% Else:
%%   If K >= 1 and K < L  yields:
%%     <K-th undelimited argument from <sequence of L consecutive undelimited 
%%      arguments>>
%%   If K < 1 or K > L
%%     (-> there is no K-th argument in the
%%         <sequence of L consecutive undelimited arguments> )
%%   yields nothing  but removal of <sequence of L consecutive 
%%          undelimited arguments>
\newcommand\KeepKthOfLArguments[2]{%
  % #1: <integer number K>
  % #2: <integer number L>
  \romannumeral0%
  \expandafter\UD@KeepKthOfLArgumentsKSmallerOneFork
  \expandafter{\romannumeral\number\number#1 000\expandafter}%
  \expandafter{\romannumeral\number\number#2 000}%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsKSmallerOneFork[2]{%
  % #1: <K letters m>
  % #2: <L letters m >
  \UD@CheckWhetherNull{#1}{% K is smaller than one:
    \UD@KeepKthOfLArgumentsRemoveNArguments{#2}{ }{}%
  }{% K is not smaller than one:
    \expandafter\UD@PassFirstToSecond
    \expandafter{%
      \UD@firstoftwo{}#1%
    }{%
      \UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop{#1}{#2}%
    }{#2}%
  }%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop[4]{%
  % #1: <K letters m>  
  % #2: <L letters m>
  % (For detecting whether K>L or K<=L, during the loop letters m will
  %  be removed both from #1 and #2 until at least one of these arguments 
  %  is empty.
  %  When the loop terminates due to #1 being empty, this implies
  %  K<=L #1. In this case #2 will hold an amount of letters m
  %  corresponding to the the difference L-K.
  %  When the loop terminates due to #2 being empty and #1 not
  %  being empty, this implies K>L.
  % )
  % #3: <K-1 letters m>
  % #4: <L letters m>
  % (#3 and #4 will be left untouched during the loop so they can be 
  %  used for performing the appropriate action when the loop
  %  terminates as it is known whether K>L.)
  \UD@CheckWhetherNull{#1}{% We have K<=L:
    \UD@KeepKthOfLArgumentsRemoveNArguments{%
      #3%
    }{%
      \UD@KeepKthOfLArgumentsRemoveNArguments{#2}{ }%
    }{}%
  }{%
    \UD@CheckWhetherNull{#2}{% We have K>L:
      \UD@KeepKthOfLArgumentsRemoveNArguments{#4}{ }{}%
    }{% We don't know yet whether K<=L or K>L, thus remove letters m and 
      % do another iteration:
      \expandafter\UD@PassFirstToSecond
      \expandafter{%
        \UD@firstoftwo{}#2%
      }{%
        \expandafter\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop
        \expandafter{%
          \UD@firstoftwo{}#1%
        }%
      }{#3}{#4}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% \UD@KeepKthOfLArgumentsRemoveNArguments{<N letters m>}%
%%                                        {<argument 1>}%
%%                                        {<argument 2>}%
%%                                        <sequence of consecutive 
%%                                         undelimited arguments>
%%.............................................................................
%% Removes the first N undelimited arguments from the <sequence of 
%% consecutive undelimited arguments>, then inserts  
%% <argument 1><argument 2>
%%
%% On the one hand when providing <argument 2> empty, you can use 
%% <argument 1> for nesting calls to \UD@KeepKthOfLArgumentsRemoveNArguments.
%% On the other hand you can provide a <space token> for stopping
%% \romannumeral-expansion as  <argument 1> and have the
%% macro grab the <K-th undelimited argument> from the <sequence of L 
%% consecutive undelimited arguments> as <argument 2>.
%%
\newcommand\UD@KeepKthOfLArgumentsRemoveNArguments[3]{%
  %% #1: <N letters m>  
  %% #2: <Argument 1>   
  %% #3: <Argument 2>
  \UD@CheckWhetherNull{#1}{#2#3}{%
    \UD@firstoftwo{%
      \expandafter\UD@KeepKthOfLArgumentsRemoveNArguments
      \expandafter{%
        \UD@firstoftwo{}#1%
      }{#2}{#3}%
    }%
  }%
}%
%%-----------------------------------------------------------------------------
%% End of code for \KeepKthOfLArguments.
\makeatother

\newcommand\MacroWithThirtyNestedParameters[1]{%
  This is paramter 1: \textbf{\KeepKthOfLArguments{1}{30}#1}\\
  This is paramter 2: \textbf{\KeepKthOfLArguments{2}{30}#1}\\
  This is paramter 3: \textbf{\KeepKthOfLArguments{3}{30}#1}\\
  This is paramter 4: \textbf{\KeepKthOfLArguments{4}{30}#1}\\
  This is paramter 5: \textbf{\KeepKthOfLArguments{5}{30}#1}\\
  This is paramter 6: \textbf{\KeepKthOfLArguments{6}{30}#1}\\
  This is paramter 7: \textbf{\KeepKthOfLArguments{7}{30}#1}\\
  This is paramter 8: \textbf{\KeepKthOfLArguments{8}{30}#1}\\
  This is paramter 9: \textbf{\KeepKthOfLArguments{9}{30}#1}\\
  This is paramter 10: \textbf{\KeepKthOfLArguments{10}{30}#1}\\
  This is paramter 11: \textbf{\KeepKthOfLArguments{11}{30}#1}\\
  This is paramter 12: \textbf{\KeepKthOfLArguments{12}{30}#1}\\
  This is paramter 13: \textbf{\KeepKthOfLArguments{13}{30}#1}\\
  This is paramter 14: \textbf{\KeepKthOfLArguments{14}{30}#1}\\
  This is paramter 15: \textbf{\KeepKthOfLArguments{15}{30}#1}\\
  This is paramter 16: \textbf{\KeepKthOfLArguments{16}{30}#1}\\
  This is paramter 17: \textbf{\KeepKthOfLArguments{17}{30}#1}\\
  This is paramter 18: \textbf{\KeepKthOfLArguments{18}{30}#1}\\
  This is paramter 19: \textbf{\KeepKthOfLArguments{19}{30}#1}\\
  This is paramter 20: \textbf{\KeepKthOfLArguments{20}{30}#1}\\
  This is paramter 21: \textbf{\KeepKthOfLArguments{21}{30}#1}\\
  This is paramter 22: \textbf{\KeepKthOfLArguments{22}{30}#1}\\
  This is paramter 23: \textbf{\KeepKthOfLArguments{23}{30}#1}\\
  This is paramter 24: \textbf{\KeepKthOfLArguments{24}{30}#1}\\
  This is paramter 25: \textbf{\KeepKthOfLArguments{25}{30}#1}\\
  This is paramter 26: \textbf{\KeepKthOfLArguments{26}{30}#1}\\
  This is paramter 27: \textbf{\KeepKthOfLArguments{27}{30}#1}\\
  This is paramter 28: \textbf{\KeepKthOfLArguments{28}{30}#1}\\
  This is paramter 29: \textbf{\KeepKthOfLArguments{29}{30}#1}\\
  This is paramter 30: \textbf{\KeepKthOfLArguments{30}{30}#1}%
}%

\begin{document}

\noindent
\MacroWithThirtyNestedParameters{%
  {Word 1}%
  {Word 2}%
  {Word 3}%
  {Word 4}%
  {Word 5}%
  {Word 6}%
  {Word 7}%
  {Word 8}%
  {Word 9}%
  {Word 10}%
  {Word 11}%
  {Word 12}%
  {Word 13}%
  {Word 14}%
  {Word 15}%
  {Word 16}%
  {Word 17}%
  {Word 18}%
  {Word 19}%
  {Word 20}%
  {Word 21}%
  {Word 22}%
  {Word 23}%
  {Word 24}%
  {Word 25}%
  {Word 26}%
  {Word 27}%
  {Word 28}%
  {Word 29}%
  {Word 30}%
}%

\vfill

\noindent\verb|\KeepKthOfLArguments| does deliver the result after two
expansion-steps:

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \KeepKthOfLArguments{3}{11}{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \KeepKthOfLArguments{3}{11}{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}%
}%

\noindent\texttt{\string\test: \meaning\test}%

\vfill\vfill

\end{document}

enter image description here


In case you don't like to specify the amount of undelimited arguments but only which one to pick, if present, I can offer a macro \ExtractKthArg.

When doing macro-programming, you can pass an arbitrary sequence of undelimited arguments via nesting that sequence into a single undelimited macro argument and apply \ExtractKthArg on that single argument for extracting a specific element from the sequence.

\documentclass{article}

\pagestyle{empty}

\makeatletter
%% Code for \ExtractKthArg
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, 
%%    \UD@CheckWhetherNull,
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@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>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \ExtractKthArg{<integer K>}{<list of undelimited arguments>} 
%% 
%% In case there is no K-th argument in <list of undelimited arguments> : 
%%   Does not deliver any token.
%% In case there is a K-th argument in <list of undelimited arguments> : 
%%   Does deliver that K-th argument with one level of braces removed.
%%
%% Examples:
%%
%%   \ExtractKthArg{0}{ABCDE} yields: <nothing>
%%
%%   \ExtractKthArg{3}{ABCDE} yields:  C
%%
%%   \ExtractKthArg{3}{AB{CD}E} yields:  CD
%%
%%   \ExtractKthArg{4}{{001}{002}{003}{004}{005}} yields: 004
%%
%%   \ExtractKthArg{6}{{001}{002}{003}} yields: <nothing> 
%% 
%%=============================================================================
\newcommand\ExtractKthArg[1]{%
  \romannumeral0%
  % #1: <integer number K>
  \expandafter\UD@ExtractKthArgCheck
  \expandafter{\romannumeral\number\number#1 000}%
}%
\newcommand\UD@ExtractKthArgCheck[2]{%
  \UD@CheckWhetherNull{#1}{ }{%
    \expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}{#2}%
  }%
}%
\newcommand\UD@ExtractKthArgLoop[2]{%
  \UD@CheckWhetherNull{#2}{ }{%
    \UD@CheckWhetherNull{#1}{%
      \UD@ExtractFirstArgLoop{#2\UD@SelDOm}%
    }{%
      \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#2}%
      {\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}}%
    }%
  }%
}%
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {\UD@firstoftwo{\expandafter}{} \UD@secondoftwo{}#1}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%% End of code for \ExtractKthArg.
\makeatother

\newcommand\MacroWithThirtyNestedParameters[1]{%
  This is paramter 1: \textbf{\ExtractKthArg{1}{#1}}\\
  This is paramter 2: \textbf{\ExtractKthArg{2}{#1}}\\
  This is paramter 3: \textbf{\ExtractKthArg{3}{#1}}\\
  This is paramter 4: \textbf{\ExtractKthArg{4}{#1}}\\
  This is paramter 5: \textbf{\ExtractKthArg{5}{#1}}\\
  This is paramter 6: \textbf{\ExtractKthArg{6}{#1}}\\
  This is paramter 7: \textbf{\ExtractKthArg{7}{#1}}\\
  This is paramter 8: \textbf{\ExtractKthArg{8}{#1}}\\
  This is paramter 9: \textbf{\ExtractKthArg{9}{#1}}\\
  This is paramter 10: \textbf{\ExtractKthArg{10}{#1}}\\
  This is paramter 11: \textbf{\ExtractKthArg{11}{#1}}\\
  This is paramter 12: \textbf{\ExtractKthArg{12}{#1}}\\
  This is paramter 13: \textbf{\ExtractKthArg{13}{#1}}\\
  This is paramter 14: \textbf{\ExtractKthArg{14}{#1}}\\
  This is paramter 15: \textbf{\ExtractKthArg{15}{#1}}\\
  This is paramter 16: \textbf{\ExtractKthArg{16}{#1}}\\
  This is paramter 17: \textbf{\ExtractKthArg{17}{#1}}\\
  This is paramter 18: \textbf{\ExtractKthArg{18}{#1}}\\
  This is paramter 19: \textbf{\ExtractKthArg{19}{#1}}\\
  This is paramter 20: \textbf{\ExtractKthArg{20}{#1}}\\
  This is paramter 21: \textbf{\ExtractKthArg{21}{#1}}\\
  This is paramter 22: \textbf{\ExtractKthArg{22}{#1}}\\
  This is paramter 23: \textbf{\ExtractKthArg{23}{#1}}\\
  This is paramter 24: \textbf{\ExtractKthArg{24}{#1}}\\
  This is paramter 25: \textbf{\ExtractKthArg{25}{#1}}\\
  This is paramter 26: \textbf{\ExtractKthArg{26}{#1}}\\
  This is paramter 27: \textbf{\ExtractKthArg{27}{#1}}\\
  This is paramter 28: \textbf{\ExtractKthArg{28}{#1}}\\
  This is paramter 29: \textbf{\ExtractKthArg{29}{#1}}\\
  This is paramter 30: \textbf{\ExtractKthArg{30}{#1}}%
}%

\begin{document}

\vspace*{-1in}\enlargethispage{1in}

\noindent\verb|\ExtractKthArg{-1}{ABCDE}|: \ExtractKthArg{-1}{ABCDE}\\
\verb|\ExtractKthArg{0}{ABCDE}|: \ExtractKthArg{0}{ABCDE}\\
\verb|\ExtractKthArg{1}{ABCDE}|: \ExtractKthArg{1}{ABCDE}\\
\verb|\ExtractKthArg{2}{ABCDE}|: \ExtractKthArg{2}{ABCDE}\\
\verb|\ExtractKthArg{3}{ABCDE}|: \ExtractKthArg{3}{ABCDE}\\
\verb|\ExtractKthArg{4}{ABCDE}|: \ExtractKthArg{4}{ABCDE}\\
\verb|\ExtractKthArg{5}{ABCDE}|: \ExtractKthArg{5}{ABCDE}\\
\verb|\ExtractKthArg{6}{ABCDE}|: \ExtractKthArg{6}{ABCDE}

\vfill

\noindent
\MacroWithThirtyNestedParameters{%
  {Word 1}%
  {Word 2}%
  {Word 3}%
  {Word 4}%
  {Word 5}%
  {Word 6}%
  {Word 7}%
  {Word 8}%
  {Word 9}%
  {Word 10}%
  {Word 11}%
  {Word 12}%
  {Word 13}%
  {Word 14}%
  {Word 15}%
  {Word 16}%
  {Word 17}%
  {Word 18}%
  {Word 19}%
  {Word 20}%
  {Word 21}%
  {Word 22}%
  {Word 23}%
  {Word 24}%
  {Word 25}%
  {Word 26}%
  {Word 27}%
  {Word 28}%
  {Word 29}%
  {Word 30}%
}%

\vfill

\noindent\verb|\ExtractKthArg| does deliver the result after two
expansion-steps:

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \ExtractKthArg{3}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
  \ExtractKthArg{3}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}}%
}%

\noindent\texttt{\string\test: \meaning\test}%

\vfill\vfill

\end{document}    

enter image description here

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.