2

Is there a way to perform a math calculation to specify a parameter? So, inside my command's definition, instead of writing #3 to specify the third parameter, is there a way to let a calculation like, #{1+2}, do that form me? I've tried that one and it doesn't work, but is there something similar that will achieve this?

  • 3
    you can have a "command that defines a command" in which you could do something like that but not something that is usable when you use the command (but there are other ways if selecting which argument to use which do not need this) what is your actual use case? – David Carlisle Sep 14 '19 at 20:08
  • I'm trying to create a command to permute the answers to my multiple choice questions. I am thinking of two commands,\MCQ which takes 5 arguments and actually formats the multiple choice question. My second command is \MCQrand which takes 5 arguments and calls MCQ, but permutes the arguments as it calls MCQ. – Allen O'Hara Sep 14 '19 at 20:11
  • 1
    I posted what is probably the nearest thing to an answer to your question, but I suspect if you asked a clearer question about your use case, someone would be able to answer that directly without syntactic tricks like this. – David Carlisle Sep 14 '19 at 20:18

4 Answers4

2

enter image description here

\def\zz#1#2{%
 \edef\zzz##1##2##3{use argument #1+#2: ##\the\numexpr#1+#2\relax}%
}

\zz{1}{1}\zzz A B C

\zz{1}{2}\zzz A B C

\bye
David Carlisle
  • 757,742
0

Not exactly what you are asking for, but another approach is to store all the arguments in an array-like structure and then retrieve the individual entries by their index.

In the following example, \setargs{{<arg1>}{<arg2>}...} stores each argument in a global macro. When a specific value should be used, you can get the value with \getarg{<numexpr>}, where <numexpr> can be a number, a counter or a simple math expression. The code doesn't do a range check for the index.

\documentclass{article}

\makeatletter
\newcommand\setargs[1]{%
    \begingroup
    \count0=1
    \setargs@#1{}\@end
    \endgroup
}
\def\setargs@#1#2\@end{%
    \expandafter\gdef\csname temp@arg@\the\count0\endcsname{#1}%
    \advance\count0 by 1
    \if\relax\detokenize{#2}\relax\else
        \setargs@#2\@end
    \fi
}

\newcommand\getarg[1]{%
    \csname temp@arg@\the\numexpr#1\endcsname
}
\makeatother

\def\foo#1#2#3{%
    \setargs{{#1}{#2}{#3}}%
    \getarg{3}%
    \getarg{\value{page}}%
    \getarg{1+1}%
}

\begin{document}

\foo{a}{b}{c}

\end{document}
siracusa
  • 13,411
0

If ε-TeX-extensions are available, or some other package for calculating numbers only by means of expansion is available, e.g. the package intcalc or the package bigintcalc, you can do something like this:

\def\PassFirstToSecond#1#2{#2{#1}}

\def\varA{4} \newcount\cntB \cntB=-1 \relax

\expandafter\def\expandafter\testA\expandafter#\expandafter1% \expandafter#\expandafter2\expandafter#\expandafter3\expandafter{% \expandafter#\the\numexpr\varA+\the\cntB }% \show\testA

\expandafter\PassFirstToSecond\expandafter{% \expandafter#\the\numexpr\varA+\the\cntB\relax }{\def\testB#1#2#3}% \show\testB

\edef\testC#1#2#3{% \expandafter#\the\numexpr\varA+\the\cntB\relax }% \show\testC

\csname bye\endcsname \stop

The console-output is:

This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2019/dev/Debian) (preloaded format=pdflatex)
entering extended mode
(./test.tex
LaTeX2e <2018-12-01>
> \testA=macro:
#1#2#3->#3.
l.12     \show\testA

? > \testB=macro: #1#2#3->#3. l.17 \show\testB

? > \testC=macro: #1#2#3->#3. l.22 \show\testC

? ) No pages of output. Transcript written on test.log.

The workflow is:

Have the calculated parameter-number expanded into the definition-text before defining is carried out.
There are various expansion-tricks for this.

When doing "\expandafter-hopping", you can treat the hash # like any other token.

But be aware that with definitions inside definitions two hashes collapse into one when the macro for performing the inner definition is expanded, thus in such situations "\expandafter-hopping" should look like this: ...\expandafter##\the\numexpr....


If it is only about permuting the elements of a list of non-delimited=brace-nested macro arguments, probably with removal of the braces that surround the single arguments in the permuted list, then I'd suggest some \romannumeral-expansion-based interface.

I elaborate on that in my second answer.

Ulrich Diez
  • 28,770
0

This is my promised second answer

If it is only about permuting the elements of a list of non-delimited=brace-nested macro arguments, probably with removal of the braces that surround the single arguments in the permuted list, then I'd suggest some \romannumeral-expansion-based interface like:

\SelectArgsInBraces{&langle;list of numbers {N_1}{N_2}..{N_L}&rangle;}%
{&langle;list of undelimited arguments&rangle;}

{&langle;list of problematic numbers&rangle;}%
{%&langle;list of selected arguments&rangle;:
  {&langle;N_1-th element of the &langle;list of undelimited arguments&rangle;&rangle;}%
  {&langle;N_2-th element of the &langle;list of undelimited arguments&rangle;&rangle;}%
  ...
  {&langle;N_L-th element of the &langle;list of undelimited arguments&rangle;&rangle;}%
}

respective

\SelectArgsWithoutBraces{&langle;list of numbers {N_1}{N_2}..{N_L}&rangle;}%
{&langle;list of undelimited arguments&rangle;}

{&langle;list of problematic numbers&rangle;}%
{%&langle;list of selected arguments&rangle;:
  &langle;N_1-th element of the &langle;list of undelimited arguments&rangle;&rangle;%
  &langle;N_2-th element of the &langle;list of undelimited arguments&rangle;&rangle;%
  ...
  &langle;N_L-th element of the &langle;list of undelimited arguments&rangle;&rangle;%
}

The ⟨list of problematic numbers⟩ holds the list of those numbers N_P where an N_P-th element does not exist within the ⟨list of undelimited arguments⟩.

The two lists can be passed to a macro which processes two arguments. Here the ⟨list of problematic numbers⟩ would be the first argument and the ⟨list of selected arguments⟩ would be the second argument. If you wish to simply ignore problematic numbers while just delivering the ⟨list of selected arguments⟩, such a macro could simply spit out its second argument. Such a macro could as well evaluate its first argument/the ⟨list of problematic numbers⟩ for delivering a more detailed error-message in case that list is not empty.

E.g.,

\SelectArgsInBraces{%
  % list of numbers {N_1}{N_2}..{N_L}
  {4}{1}{3}{23}{4}{15}{17}%
}{%
  % list of undelimited arguments:
  {one}{two}{three}{four}{five}{six}{seven}{eight}%
  {nine}{ten}{eleven}{twelve}{thirteen}{fourteen}{fifteen}%
}%

{{23}{17}}{{four}{one}{three}{four}{fifteen}}%

(The ⟨list of problematic numbers⟩ contains the numbers 23 and 17 because the ⟨list of undelimited arguments⟩ in this case does neither have a 23-th nor a 17-th element.

respective

\SelectArgsWithoutBraces{%
  % list of numbers {N_1}{N_2}..{N_L}
  {4}{1}{3}{23}{4}{15}{17}%
}{%
  % list of undelimited arguments:
  {one }{two }{three }{four }{five }{six }{seven }{eight }%
  {nine }{ten }{eleven }{twelve }{thirteen }{fourteen }{fifteen }%
}%

{{23}{17}}{four one three four fifteen }%

(The ⟨list of problematic numbers⟩ contains the numbers 23 and 17 because the ⟨list of K undelimited arguments⟩ in this case does neither have a 23-th nor a 17-th element.

Such a macro can also be used for permuting/multiplying/removing arguments from a list of arguments.

In the coding-example below I implemented things in a way where the numbers N_1, N_2,..,N_L are evaluated via \number during macro-expansion.

The advantage is:

You can provide numbers in terms of whatsoever expressions that expand to valid TeX-⟨number⟩-quantities.
E.g., in terms of ε-TeX's \numexpr.
E.g., in terms of the macros of the packages intcalc/bigintcalc.

The disadvantage is:

You face all kinds of inscrutable error-messages in case such an expression does not evaluate to a valid TeX-⟨number⟩-quantity.

(A test which in all situations predicts whether an arbitrary sequence of tokens evaluates to a valid TeX-⟨number⟩-quantity is not feasible: An arbitrary sequence of tokens implies the possibility of carrying out arbitrary expansion-based algorithms. Thus one faces the halting-problem.)

\makeatletter
%%=============================================================================
%% Paraphernalia:
%%    \UD@stopromannumeral, \UD@firstoftwo, \UD@secondoftwo, \UD@exchange,
%%    \UD@PassFirstToSecond,  \UD@CheckWhetherNull
%%=============================================================================
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@exchange[2]{#2#1}%
\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]{%
  \romannumeral\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
  \expandafter\UD@stopromannumeral\@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \ExtractKthArgInBraces{<integer K>}%
%%                       {<tokens in case list of undelimited args doesn't have a k-th argument>}%
%%                       {<list of undelimited arguments>} 
%% 
%% In case there is no K-th argument in <list of indelimited arguments> : 
%%   <tokens in case list of undelimited args doesn't have a k-th argument>
%% In case there is a K-th argument in <list of indelimited arguments> : 
%%   Does deliver that K-th argument nested in braces.
%% If you leave <tokens in case list of undelimited args doesn't have a k-th argument> empty,
%% then the case of there not being a k-th-argument in the list can be cranked out as then
%% only in case of there not being a k-th-argument nothing/emptiness is returned by 
%% \ExtractKthArgInBraces.
%%
%%     Examples:
%%
%%       \ExtractKthArgInBraces{0}{not available}{ABCDE} yields: not available
%%
%%       \ExtractKthArgInBraces{3}{not available}{ABCDE} yields:  {C}
%%
%%       \ExtractKthArgInBraces{3}{not available}{AB{CD}E} yields:  {CD}
%%
%%       \ExtractKthArgInBraces{4}{not available}{{001}{002}{003}{004}{005}} yields: {004}
%%
%%       \ExtractKthArgInBraces{6}{not available}{{001}{002}{003}} yields: not available
%% 
%% Due to \romannumeral-expansion the result is delivered after two
%% expansion-steps/after two "hits" from \expandafter.
%%
%%
%% \ExtractKthArgWithoutBraces{<integer K>}
%%                            {<tokens in case list of undelimited args doesn't have a k-th argument>}%
%%                            {<list of undelimited arguments>} 
%% 
%% In case there is no K-th argument in <list of indelimited arguments> : 
%%   <tokens in case list of undelimited args doesn't have a k-th argument>
%% In case there is a K-th argument in <list of indelimited arguments> : 
%%   Does deliver that K-th argument with one level of surrounding braces
%%   removed if present.
%%
%%     Examples:
%%
%%       \ExtractKthArgWithoutBraces{0}{not available}{ABCDE} yields: not available
%%
%%       \ExtractKthArgWithoutBraces{3}{not available}{ABCDE} yields:  C
%%
%%       \ExtractKthArgWithoutBraces{3}{not available}{AB{CD}E} yields:  CD
%%
%%       \ExtractKthArgWithoutBraces{4}{not available}{{001}{002}{003}{004}{005}} yields: 004
%%
%%       \ExtractKthArgWithoutBraces{6}{not available}{{001}{002}{003}} yields: not available
%% 
%% Due to \romannumeral-expansion the result is delivered after two
%% expansion-steps/after two "hits" from \expandafter.
%%.............................................................................
\newcommand\ExtractKthArgInBraces[1]{%
  % #1: <integer number K>
  \romannumeral\expandafter\UD@ExtractKthArgCheck\expandafter{\romannumeral\number\number#1 000}{{}}%
}%
\newcommand\ExtractKthArgWithoutBraces[1]{%
  % #1: <integer number K>
  \romannumeral\expandafter\UD@ExtractKthArgCheck\expandafter{\romannumeral\number\number#1 000}{}%
}%
\newcommand\UD@ExtractKthArgCheck[4]{%
  % #1: In case K is not positive: empty.
  %     In case K is positive: Letters m whose amount corresponds to 
  %                            <integer number K>
  % #2: <brace removal indicator; if empty, then one level of braces gets removed>
  % #3: <tokens in case list of undelimited args doesn't have a k-th argument>
  % #4: <list of undelimited arguments>
  \UD@CheckWhetherNull{#1}{%
    % K is not positive, thus there is no K-th element.
    \UD@stopromannumeral#3%
  }{%
    % K is positive, thus let's start the loop for removing elements until
    % either the list is empty or the (formerly) K-th argument is the first
    % argument of the list.
    \expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}{#2}{#3}{#4}%
  }%
}%
\begingroup
\def\UD@ExtractFirstArgLoop#1{%
  % #1 is frozen-\relax
  \endgroup
  \@ifdefinable\UD@RemoveTillFrozenrelax{\long\def\UD@RemoveTillFrozenrelax##1##2#1{{##1}}}%
  \newcommand\UD@ExtractFirstArgWithoutBraces[1]{\romannumeral\UD@ExtractFirstArgLoop{##1#1}{}}%
  \newcommand\UD@ExtractFirstArgInBraces[1]{\romannumeral\UD@ExtractFirstArgLoop{##1#1}{{}}}%
  \newcommand\UD@ExtractKthArgLoop[4]{%
    % ##1: Letters m 
    % ##2: <brace removal indicator; if empty, then one level of braces gets removed>
    % ##3: <tokens in case list of undelimited args doesn't have a k-th argument>
    % ##4: <list of undelimited arguments>
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo##4{}{}}{%
      % The remaining <list of undelimited arguments> is blank, i.e. empty or
      % only holding spaces, thus there is no K-th argument in that list. 
      \UD@stopromannumeral##3%
    }{%
      \UD@CheckWhetherNull{##1}{%
        % There are no letters "m" left, thus the now first argument of the
        % remaining <list of undelimited arguments> is the (formerly) K-th
        % argument to extract, thus let's now start the loop for removing the
        % elements behind it while keeping it:
        \UD@ExtractFirstArgLoop{##4#1}{##2}%
      }{%
        % There are still letters "m" in #1, thus you still need to remove
        % elements both from the remaining <list of undelimited arguments> and
        % from the list of letters "m":
        \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}##4}%
        {\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}##1}{##2}{##3}}%
      }%
    }%
  }%
}%
\expandafter\expandafter\expandafter\UD@ExtractFirstArgLoop
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\ifnum0=0\fi}%
%% Usage of frozen-\relax as delimiter is for speeding things up by reducing the
%% amount of iterations needed. I chose frozen-\relax because David Carlisle 
%% pointed out in   <https://tex.stackexchange.com/a/578877>
%% that frozen-\relax cannot be (re)defined in terms of \outer and cannot be
%% affected by \uppercase/\lowercase.
%%
%% \UD@ExtractFirstArg's argument may contain frozen-\relax:
%% The only effect is that internally more iterations are needed for
%% obtaining the result.
\newcommand\UD@ExtractFirstArgLoop[2]{%
    % \UD@ExtractFirstArgLoop with each element of a list of frozen-\relax-
    % delimited list splits the first undelimited component, keeps it, nested
    % in curly braces (which implies that in the next removal-iteration it will
    % again be the first component), and throws away the remainder and the 
    % frozen-\relax-Delimiter. As it is ensured that at the beginning of the loop
    % the list has a trailing frozen-\relax, at some stage, when all
    % frozen-\relax-elements were processed, only the very first undelimited
    % component of the list remains.
    % This way using frozen-\relax is not forbidden to the user if s/he insists in
    % doing so.
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {%
    \UD@CheckWhetherNull{#2}{%
      \expandafter\UD@stopromannumeral\UD@firstoftwo#1{}%
    }{\UD@stopromannumeral#1}%
  }%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillFrozenrelax#1}{#2}}%
}%
%% End of code for \ExtractKthArgInBraces/\ExtractKthArgWithoutBraces.
%%=============================================================================
%% Select several arguments from a list of undelimited arguments:
%%
%% \SelectArgsInBraces{<list of numbers {N_1}..{N_L}>}%
%%                    {<list of undelimited arguments>}%
%%  yields:
%%   {<list of problematic elements>}%
%%   {% <list of selected elements>:
%%      {N_1-th element of <list of undelimited arguments>}%
%%      ..
%%      {N_L-th element of <list of undelimited arguments>}%
%%   }%
%%  , each element nested in braces.
%%
%% \SelectArgsWithoutBraces{<list of numbers {N_1}..{N_L}>}%
%%                         {<list of undelimited arguments>}%
%%  yields:
%%   {<list of problematic elements>}%
%%   {% <list of selected elements>:
%%      N_1-th element of <list of undelimited arguments>%
%%      ..
%%      N_L-th element of <list of undelimited arguments>%
%%   }%
%%  , each element without outermost surrounding braces if previously present.
%%
%% Elements can be selected several times.
%% Usually the <list of problematic elements> should be empty.
%% In case some number N_P denotes an element which the list does not have, 
%% that number N_P is in the <list of problematic elements>. Duplicates in
%% that list are not checked.
%% If the <list of selected elements> is empty, this means that the
%% <list of numbers {N_1}..{N_L}>  did not denote elements which the
%% <list of undelimited arguments> does have.
%%
%% \SelectArgsInBraces/\SelectArgsWithoutBraces forms a tail-recursive loop
%% for calling \ExtractKthArgInBraces.
%%
%% Due to \romannumeral-expansion the result is delivered after two
%% expansion-steps/after two "hits" from \expandafter.
%%.............................................................................
\newcommand\SelectArgsInBraces[2]{%
   % #1 = <list of numbers N_1..N_L>
   % #2 = <list of undelimited arguments>
   \romannumeral\InnerSelectArgs{}{}{#1}{#2}{{}}%
}%
\newcommand\SelectArgsWithoutBraces[2]{%
   % #1 = <list of numbers N_1..N_L>
   % #2 = <list of undelimited arguments>
   \romannumeral\InnerSelectArgs{}{}{#1}{#2}{}%
}%
%%-----------------------------------------------------------------------------
%% \InnerSelectArgs{<list of problematic numbers>}%
%%                 {<list of selected arguments>}%
%%                 {<list of numbers {N_1}..{N_L}>}%
%%                 {<list of undelimited arguments>}%
%%                 {<brace-nesting-indicator; 
%%                   if empty, then elements shall not be surrounded by braces>}%
%%.............................................................................
\newcommand\InnerSelectArgs[5]{%
  %% #1 = <list of problematic elements>
  %% #2 = <list of selected arguments>
  %% #3 = <list of numbers {N_1}..{N_L}>
  %% #4 = <list of undelimited arguments>
  %% #5 = <brace-nesting-indicator; 
  %%       if empty, then elements shall not be surrounded by braces>}%
  \expandafter\UD@CheckWhetherNull
  \expandafter{\UD@firstoftwo#3{}{}}{\UD@stopromannumeral{#1}{#2}}{%
    \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#3}{%
      \expandafter\UD@CheckWhetherNull\expandafter{%
        \romannumeral
        \expandafter\expandafter\expandafter\expandafter\expandafter
        \expandafter\expandafter\expandafter\expandafter\expandafter
        \expandafter\expandafter\expandafter\expandafter\expandafter
        \UD@stopromannumeral
        \expandafter\expandafter\expandafter\ExtractKthArgInBraces
        \UD@ExtractFirstArgInBraces{#3}{}{#4}%
      }{%
        \UD@PassFirstToSecond{#2}{%
          \expandafter\UD@PassFirstToSecond\expandafter{%
            \romannumeral\expandafter\expandafter\expandafter\UD@PassFirstToSecond
            \UD@ExtractFirstArgInBraces{#3}{\UD@stopromannumeral#1}%
          }{\InnerSelectArgs}%
        }%
      }{%
        \expandafter\UD@PassFirstToSecond\expandafter{%
          \romannumeral
          \UD@CheckWhetherNull{#5}{\expandafter\UD@exchange}%
                                  {\expandafter\UD@PassFirstToSecond}%
          \romannumeral
          \expandafter\expandafter\expandafter\expandafter\expandafter
          \expandafter\expandafter\expandafter\expandafter\expandafter
          \expandafter\expandafter\expandafter\expandafter\expandafter
          \UD@stopromannumeral
          \expandafter\expandafter\expandafter\ExtractKthArgInBraces
          \UD@ExtractFirstArgInBraces{#3}{}{#4}{\UD@stopromannumeral#2}%
        }{%
          \UD@PassFirstToSecond{#1}{\InnerSelectArgs}%
        }%
      }%
    }{#4}{#5}%
  }%
}%
%%=============================================================================
%%=============================================================================
%% Error-message in case the <list of numbers {N_1}..{N_L}> denotes elements
%% which the <list of undelimited arguments> does not have:
%%.............................................................................
%% \UD@InvalidArgSpecifiersError{<name of command which triggers the 
%%                                error-message>}%
%%                              {<list of problematic elements>}%
%%                              {<syntax descriptor of argument that holds 
%%                               <list of undelimited arguments> >}%
%%                              {<syntax descriptor of argument that holds
%%                               <list of numbers {N_1}..{N_L}> >}%
%% <syntax descriptor of...> is to hold a phrase like  fifth non-optional".
\newcommand\UD@InvalidArgSpecifiersError[4]{%
  \begingroup
  \toks@{#2}%
  \GenericError{%
    \@backslashchar#1\space\@spaces
  }{%
    \@backslashchar#1-error\on@line:\MessageBreak
    Invalid arguments `\the\toks@' specified%
  }{%
    See the comments of this file for explanation.%
  }{%
    The #3 argument of \@backslashchar#1 holds a list of%
    \MessageBreak
    non-delimited arguments whereof elements can be selected via the%
    \MessageBreak
    number-list in the #4 argument.%
    \MessageBreak
    Seems the number-list in the #4 argument denotes%
    \MessageBreak
    arguments which the list in the #3 argument does not have.%
  }%
  \endgroup
}%
%%=============================================================================
%% Now for the sake of having fun a user-level-macro where you can specify
%% a <list of numbers {N_1}..{N_L}> and a <list of undelimited arguments>
%% and which throws an error-message in case <list of numbers {N_1}..{N_L}>
%% denotes arguments which the <list of undelimited arguments> does not
%% have and which defines the macro `\tempa` to expand to the resulting
%% <list of selected arguments> and which then displays the meaning
%% of \tempa:
\newcommand\ShowBracedSelection[2]{%
   \expandafter\expandafter\expandafter\ShowSelection
   \SelectArgsInBraces{#1}{#2}{ShowBracedSelection}%
}%
\newcommand\ShowNonBracedSelection[2]{%
   \expandafter\expandafter\expandafter\ShowSelection
   \SelectArgsWithoutBraces{#1}{#2}{ShowNonBracedSelection}%
}%
\newcommand\ShowSelection[3]{%
  \UD@CheckWhetherNull{#1}{}{%
    \UD@InvalidArgSpecifiersError{#3}{#1}%
                                 {second non-delimited}%
                                 {first non-delimited}%
  }%
  \begingroup
  \toks@{#2}%
  \edef\tempa{\the\toks@}%
  \texttt{\string\tempa: \meaning\tempa}%
  \endgroup
}%
%%=============================================================================
%% Now a helper-macro for the test-suite:
\newcommand\performtest[1]{%
   \begingroup
   \toks@\expandafter\expandafter\expandafter{#1}%
   \edef\tempa{\the\toks@}%
   \texttt{\expandafter\strip@prefix\meaning\tempa}%
   \endgroup
}%
\makeatother

\documentclass[landscape]{article}

\expandafter\ifx\csname pdfpagewidth\endcsname\relax\else\pdfpagewidth=\paperwidth\fi \expandafter\ifx\csname pagewidth\endcsname\relax\else\pagewidth=\paperwidth\fi \expandafter\ifx\csname pdfpageheight\endcsname\relax\else\pdfpageheight=\paperheight\fi \expandafter\ifx\csname pageheight\endcsname\relax\else\pageheight=\paperheight\fi \oddsidemargin=1cm % \textwidth=\paperwidth \advance\textwidth-2\oddsidemargin \advance\oddsidemargin-1in % \advance\oddsidemargin-\hoffset % \evensidemargin=\oddsidemargin \topmargin=1cm % \textheight=\paperheight \advance\paperheight-2\topmargin \advance\topmargin-1in % \advance\topmargin-\voffset \headheight=0ex % \headsep=0ex % \footnotesep=.66cm % \pagestyle{empty}% \parindent=0ex % \frenchspacing

\begin{document}

\verb|\ExtractKthArgWithoutBraces{-1}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgWithoutBraces{-1}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgWithoutBraces{0}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgWithoutBraces{0}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgWithoutBraces{1}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgWithoutBraces{1}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgWithoutBraces{2}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgWithoutBraces{2}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgWithoutBraces{3}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgWithoutBraces{3}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgWithoutBraces{4}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgWithoutBraces{4}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgWithoutBraces{12}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgWithoutBraces{12}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgWithoutBraces{14}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgWithoutBraces{14}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

\verb|\ExtractKthArgInBraces{-1}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgInBraces{-1}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgInBraces{0}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgInBraces{0}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgInBraces{1}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgInBraces{1}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgInBraces{2}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgInBraces{2}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgInBraces{3}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgInBraces{3}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgInBraces{4}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgInBraces{4}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgInBraces{12}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgInBraces{12}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}\ \verb|\ExtractKthArgInBraces{14}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\ExtractKthArgInBraces{14}{not available}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

\verb|\SelectArgsInBraces{{-1}{0}{1}{7}{5}{5}{5}{12}{14}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\SelectArgsInBraces{{-1}{0}{1}{7}{5}{5}{5}{12}{14}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}%

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

\verb|\SelectArgsWithoutBraces{{-1}{0}{1}{7}{5}{5}{5}{12}{14}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \performtest{\SelectArgsWithoutBraces{{-1}{0}{1}{7}{5}{5}{5}{12}{14}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}}%

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

\verb|\ShowBracedSelection{{1}{7}{5}{5}{5}{12}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \ShowBracedSelection{{1}{7}{5}{5}{5}{12}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

\verb|\ShowNonBracedSelection{{1}{7}{5}{5}{5}{12}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \ShowNonBracedSelection{{1}{7}{5}{5}{5}{12}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

\message{^^JThe next test is expected to throw an error message.% ^^JSo don't be frightened.% ^^JPress return to continue.}\immediate\read-1to\tempa \verb|\ShowBracedSelection{{-1}{0}{1}{7}{5}{5}{5}{12}{14}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \ShowBracedSelection{{-1}{0}{1}{7}{5}{5}{5}{12}{14}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

\message{^^JThe next test is expected to throw an error message.% ^^JSo don't be frightened.% ^^JPress return to continue.}\immediate\read-1to\tempa \verb|\ShowNonBracedSelection{{-1}{0}{1}{7}{5}{5}{5}{12}{14}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}|: \ShowNonBracedSelection{{-1}{0}{1}{7}{5}{5}{5}{12}{14}}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}}

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

Permute some arguments without brace-removal :

\verb|\ShowBracedSelection{{2}{7}{4}{1}{6}{3}{5}}{{one}{two}{three}{four}{five}{six}{seven}}|: \ShowBracedSelection{{2}{7}{4}{1}{6}{3}{5}}{{one}{two}{three}{four}{five}{six}{seven}}

\hrulefill\vspace{-\dp\strutbox}\vspace{\ht\strutbox}%

Permute some arguments with brace-removal :

\verb|\ShowNonBracedSelection{{2}{7}{4}{1}{6}{3}{5}}{{one}{two}{three}{four}{five}{six}{seven}}|: \ShowNonBracedSelection{{2}{7}{4}{1}{6}{3}{5}}{{one}{two}{three}{four}{five}{six}{seven}}

\end{document} %% AUTHOR %% %% Ulrich W. Diez (ud.usenetcorrespondence@web.de) %% %% LICENCE AND COPYRIGHT %% %% Copyright (C) 2019 - 2022 by Ulrich W. Diez (ud.usenetcorrespondence@web.de) %%.............................................................................. %% This work may be distributed and/or modified under the conditions of the %% LaTeX Project Public Licence (LPPL), either version 1.3 of this license or %% (at your option) any later version. %% (The latest version of this license is in: %% http://www.latex-project.org/lppl.txt %% and version 1.3 or later is part of all distributions of %% LaTeX version 1999/12/01 or later.) %% The author of this work is Ulrich Diez. %% This work has the LPPL maintenance status 'not maintained'. %% Usage of any/every component of this work is at your own risk. %% There is no warranty - neither for probably included documentation nor for %% any other part/component of this work. %% If something breaks, you usually may keep the pieces. %%//////////////////////////////////////////////////////////////////////////////

The pdf-output of this example is:

enter image description here

The console-output with this example is:

enter image description here

Ulrich Diez
  • 28,770