2

Here is my problem: I try to write a command with some arguments (let's say 4) and I need to loop on the arguments. Like this:

\documentclass[parskip=half]{scrartcl}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage{hyperref}

\usepackage{multicol}
\renewcommand{\LayoutChoiceField}[2]{%
\leavevmode #2 #1%
}
\usepackage{enumerate}
\newcounter{itemp}

\newcommand\qqc[4]{%
    \setcounter{itemp}{1}
    \textbf{Question :}
    \begin{multicols}{2}
    \begin{enumerate}
        \loop
            {%
            \item[{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]
                                                         {#{\the\value{itemp}}}\\ 
            }    
        \stepcounter{itemp}
        \ifnum \value{itemp} < 5 
        \repeat

    \end{enumerate}  
    \end{multicols}    
    }%
\begin{document}
\qqc{I'm not Bill Gates, but you already know that}{I'm not John Gates}{Nor Joshua Gates}{Neither Kevin Gates. I don't rap.}
\end{document}

Obviously, the problem is in {#{\the\value{itemp}}}. I would like to get #1, then #2, #3 and #4, but not simply the string; something I can deal with (for example to print the temp-th argument) Moreover, I don't think it is approriate to use etoolbox since we can get comma and many different symbols in the arguments, hence, no proper delimiter for a list... If you have any idea, you are more than welcome. All my best, Thierry.

5

Welcome! Rather than iterating over the arguments I would pass a list to the command and iterate over the list. If you keep loading tikz, you could use \foreach for that, but you do not necessarily need that, you could use also \@for here.

\documentclass[parskip=half]{scrartcl}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{amssymb}
\usepackage{hyperref}

\usepackage{multicol}
\renewcommand{\LayoutChoiceField}[2]{%
\leavevmode #2 #1%
}
\usepackage{enumerate}
\makeatletter
\newcommand\qqc[1]{%
    \textbf{Question :}
    \begin{multicols}{2}
    \begin{enumerate}
        \@for\temp:=#1\do{%
            \item 
            [{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]{\temp}
            }    
    \end{enumerate}  
    \end{multicols}    
    }%
\makeatother    
\begin{document}
\begin{Form}
\qqc{{I'm not Bill Gates, but you already know that},%
{I'm not John Gates},%
{Nor Joshua Gates},%
{Neither Kevin Gates. I don't rap.}}
\end{Form}

\end{document}

enter image description here

I had to wrap the code into \begin{Form} and \end{Form} and of course do not know what you have in mind.

EDIT: Removed the unnecessary counter, as pointed out by Ulrich Diez (Thanks!). This was an oversight, the content of the answer did not change.

| improve this answer | |
  • 1
    Always the same sad story. Sigh. – user194703 May 2 at 5:12
  • 1
    It is weird isn't it? You posted first with an elegant answer and then another less elegant post attracts more votes. I don't understand it either. – user30471 May 2 at 6:43
  • @UlrichDiez I am nevertheless grateful. It was a stupid oversight, which is in the worst case confusing. And no, please be assured that this was never about you. As I said, I am still shocked by the events that left to the departure of jfbu, and I do not think that concerns you. – user194703 May 2 at 7:42
  • Thank you very much. Exactly what I needed. – DuncanIdaho May 2 at 11:39
  • I was talking about the solution you provide... Not your comments! – DuncanIdaho May 2 at 11:41
5

Just use a macro to do the repetitive task. I also fixed the start of multicols, so you don't risk a page break between “Question:” and the questions.

\documentclass[parskip=half]{scrartcl}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage{enumerate}
\usepackage{multicol}

\usepackage{hyperref} % should be last


\renewcommand{\LayoutChoiceField}[2]{\leavevmode #2 #1}

\newcommand{\doitem}[1]{%
  \item[{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]{#1}
}

\newcommand\qqc[4]{%
  \textbf{Question:}
  \begin{multicols}{2}
  \begin{enumerate}
  \doitem{#1}\doitem{#2}\doitem{#3}\doitem{#4}
  \end{enumerate}  
  \end{multicols}    
}

\begin{document}

\begin{Form}
\qqc{I'm not Bill Gates, but you already know that}
    {I'm not John Gates}
    {Nor Joshua Gates}
    {Neither Kevin Gates. I don't rap.}
\end{Form}

\end{document}

enter image description here

With a change of syntax you can accommodate how many items you wish. The syntax is the same as suggested by another answer.

\documentclass[parskip=half]{scrartcl}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{amssymb}
\usepackage{tikz}
\usepackage{enumerate}
\usepackage{multicol}
\usepackage{xparse}

\usepackage{hyperref} % should be last


\renewcommand{\LayoutChoiceField}[2]{\leavevmode #2 #1}

\ExplSyntaxOn

\cs_new_protected:Nn \duncanidaho_qqc_item:n
 {
  \item[{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]{#1}
 }

\NewDocumentCommand{\qqc}{m}
 {
  \begin{multicols}{2}[\textbf{Question:}]
  \begin{enumerate}
  \tl_map_function:nN { #1 } \duncanidaho_qqc_item:n
  \end{enumerate}
  \end{multicols}
 }

\ExplSyntaxOff

\begin{document}

\begin{Form}
\qqc{
  {I'm not Bill Gates, but you already know that}
  {I'm not John Gates}
  {Nor Joshua Gates}
  {Neither Kevin Gates. I don't rap.}
}
\end{Form}

\begin{Form}
\qqc{
  {I'm not Bill Gates, but you already know that}
  {I'm not John Gates}
  {Nor Joshua Gates}
  {Neither Kevin Gates. I don't rap.}
  {Whatever}
  {Something else}
  {Stop here}
  {One more thing}
}
\end{Form}

\end{document}

enter image description here

| improve this answer | |
4

You program in LaTeX. LaTeX is based on TeX as described in the TeXbook of Donald Ervin Knuth. Basically LaTeX is just a set of macros written in TeX and packaged as a so-called format in order to have these macros loaded automatically when loading the TeX-program via an executable that is called latex/latex.exe/whatsoever. Low-level-concepts introduced in the TeXbook also apply to LaTeX. Thus in the following explanations things where I use the phrase "TeX" also apply when programming in LaTeX.

Think of TeX-macros as tokens that during expansion get removed from the token-stream and which additionally trigger the removal of more tokens from the token-stream followed by insertion of tokens into the token-stream.

"Removal of more tokens from the token-stream" is done according to the rules provided by the ⟨parameter text⟩ which belongs to the macro's ⟨definition⟩.

"Insertion of tokens into the token-stream" is done according to the rules provided by the ⟨balanced text⟩ which also belongs to the macro's ⟨definition⟩.

The tokens inserted into the token-stream form the "replacement text".

Syntax #1, #2, ..., #9 for denoting arguments of a macro is available only at the time of defining the macro/at the time of providing the ⟨definition⟩ of the macro. It is not available at the time of expanding the macro and afterwards processing the tokens which form the replacement text which comes from expanding the macro.

But a thing like #{\the\value{itemp}} is an attempt to make such syntax available at the time of expanding a macro and afterwards processing the replacement text of that macro. This is not possible in TeX.

As in TeX you cannot have processed more than nine arguments directly via a macro, i.e., without tricks like tail-recursively applying the same macro to several sets of arguments, looping over the numbers of arguments seems not needed to me. You can just do:

\documentclass[parskip=half]{scrartcl}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{amssymb}
\usepackage{hyperref}

\usepackage{multicol}
\renewcommand{\LayoutChoiceField}[2]{%
\leavevmode #2 #1%
}
\usepackage{enumerate}
\newcommand\qqc[4]{%
    \textbf{Question :}
    \begin{multicols}{2}
    \begin{enumerate}
            \item 
            [{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]{#1}%
            \item 
            [{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]{#2}%
            \item 
            [{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]{#3}%
            \item 
            [{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]{#4}%
    \end{enumerate}  
    \end{multicols}    
    }%
\begin{document}
\begin{Form}
\qqc{I'm not Bill Gates, but you already know that}{I'm not John Gates}{Nor Joshua Gates}{Neither Kevin Gates. I don't rap.}
\end{Form}

\end{document}

If you insist in having a loop where arguments can be addressed by an ordinal number denoting their position within a line-up of an arbitrary amount of arguments, I can offer a macro \ExtractKthArg{⟨integer K⟩}{⟨list of undelimited args⟩}:

\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 args>} 
%% 
%% In case there is no K-th argument in <list of undelimited args> : 
%%   Does not deliver any token.
%% In case there is a K-th argument in <list of undelimited args> : 
%%   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]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo#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
%%
%%-----------------------------------------------------------------------------
%%
\documentclass[parskip=half]{scrartcl}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{amssymb}
\usepackage{hyperref}

\usepackage{multicol}
\renewcommand{\LayoutChoiceField}[2]{%
\leavevmode #2 #1%
}
\usepackage{enumerate}
\newcounter{itemp}

\newcommand\qqc[4]{%
    \setcounter{itemp}{1}%
    \textbf{Question :}
    \begin{multicols}{2}%
    \begin{enumerate}
        \loop
            \item 
            [{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]{\ExtractKthArg{\value{itemp}}{{#1}{#2}{#3}{#4}}}%
        \stepcounter{itemp}%
        \ifnum \value{itemp} < 5 
        \repeat
    \end{enumerate}  
    \end{multicols}    
    }%
\begin{document}
\begin{Form}
\qqc{I'm not Bill Gates, but you already know that}{I'm not John Gates}{Nor Joshua Gates}{Neither Kevin Gates. I don't rap.}
\end{Form}

\end{document}

If you just wish to process all arguments one by one, but don't need the possibility of addressing/selecting/picking specific arguments, you can do tail-recursion:

\documentclass[parskip=half]{scrartcl}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{amssymb}
\usepackage{hyperref}

\usepackage{multicol}
\renewcommand{\LayoutChoiceField}[2]{%
\leavevmode #2 #1%
}

\newcommand\RecursionStopper{\RecursionStopper}%
\makeatletter
\newcommand\tailrecursive[2]{%
  % !!! #2 must not contain unbalanced \if../\else/\fi !!!
  \ifx\RecursionStopper#2%
    \expandafter\@gobble
  \else
    \expandafter\@firstofone
  \fi
   {#1{#2}\tailrecursive{#1}}%
}%
\makeatother

\usepackage{enumerate}
\newcommand\qqc[4]{%
    \textbf{Question :}
    \begin{multicols}{2}
    \begin{enumerate}
      \tailrecursive{%
         \item 
         [{\ChoiceMenu[name=Q,radio,radiosymbol=\ding{52}]{}{=1}}]%
      }{#1}{#2}{#3}{#4}{\RecursionStopper}%
    \end{enumerate}  
    \end{multicols}    
    }%
\begin{document}
\begin{Form}
\qqc{I'm not Bill Gates, but you already know that}{I'm not John Gates}{Nor Joshua Gates}{Neither Kevin Gates. I don't rap.}
\end{Form}

\end{document}

In my answer to the question "defining a new command with variable name in a loop" I describe variants of a macro \DoWithEachElementOfArgumentList. This might be of interest to you.

| improve this answer | |
  • Thanks very much. A bit complicated for me to understand but it does the job. – DuncanIdaho May 2 at 11:39

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.