0

I would like to check if something starts with an asterisk (*)

My attempt:

\def\testast#1{\ifx*#1\relax YES\else NO\fi}

But the output of \testast{*Word} is WordYES while I would expect just YES


The actual situation I need this for is the following: I'm trying to parse a database of exercises, in the form

    \begin{multi}
     Text
     \item answer 
     \item another answer
     \item* the correct answer
    \end{multi}

and find the correct answer. I use getitems.sty. My attempt is

    \newcommand\findcorrect[1]{%
      \ifx*#1 \relax\xdef\correct{\thecurrentitemnumber}%
      \fi%  
     }% 
    \NewEnviron{multi}[1][]{%
       \expandafter\gatheritems\expandafter{\BODY}
       \loopthroughitemswithcommand{\findcorrect}% 
    }%
    {}%

But as a result of this my macro prints, while running the object \gathereditems{n} when it finds the correct answer.

The problem boils down to the initial example I posted at the beginning.

  • Might be better to start by explaining you use case. There might be better solutions – daleif May 14 '22 at 10:20
  • @daleif Just edited the question explaining where my problem come from – user126154 May 14 '22 at 10:59
  • 1
    \@ifstar{yes}{no} is what latex uses for * forms of commands. – David Carlisle May 14 '22 at 11:09
  • but I'm usign getitems, so what I have in hands is a macro \gathererditem{n} which is what comes after the nth occurrence of \item, so it starts by * if we have \item*. So the string I need to test does not contain anymore the command \item – user126154 May 14 '22 at 11:20
  • You okay with expl3 or not? (alternatively if you want to learn yourself look at \tl_head and \str_if_eq, note that the former drop spaces) or just \tl_if_head_equal_charcode – user202729 May 14 '22 at 11:52
  • 1
    @user202729 no, I'm not ok with expl3. I see that I should, but I'm not. I'm ok with a simple macro expl3 that I can copy and paste on my code, I also happy if I found some place where I can learn myself. I mean: I found a 340 pages of LaTeX 3 manual, but it is not immediate to learn from that – user126154 May 14 '22 at 11:59
  • Read interface3.pdf to learn expl3, or read TeXbook (or TeX by topic) to learn TeX. Although you need all sorts of contortions to get things done in TeX, in that case you might resort to reading source3.pdf to see how it's implemented in expl3 – user202729 May 14 '22 at 12:01
  • 1
    If anythinging there a tutorial blog post linked from latex3 - Where I can find introduction to programming in expl3? - TeX - LaTeX Stack Exchange but it doesn't really touch on expansion misconception etc. – user202729 May 14 '22 at 12:03

2 Answers2

3

With \def\testast#1{\ifx*#1\relax YES\else NO\fi} the command
\testast{*Word}%
yields:
\ifx**Word\relax YES\else NO\fi.

\ifx compares the meaning of * to the meaning of *. Thus the if-branch is taken while the \else-branch is skipped while the if-branch is formed by Word\relax YES. \relax does not yield anything visible in the .pdf-file, thus in the .pdf-file you see WordYES.



\makeatletter    
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange, \UD@stopromannumeral,
%%    \UD@CheckWhetherNull,  \UD@CheckWhetherLeadingTokens
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% 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\UD@firstoftwo}%
}%
%%=============================================================================
%% Check whether argument's leading tokens form a specific 
%% token-sequence that does not contain explicit character tokens of 
%% category 1 or 2 or 6:
%%=============================================================================
%% \UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%%                              {<a <token sequence> without explicit 
%%                                character tokens of category 1 or 2
%%                                or 6>}%
%%                              {<internal token-check-macro>}%
%%                              {<tokens to be delivered in case
%%                                <argument which is to be checked> has
%%                                <token sequence> as leading tokens>}%
%%                              {<tokens to be delivered in case 
%%                                <argument which is to be checked>
%%                                does not have <token sequence> as
%%                                leading tokens>}%
\newcommand\UD@CheckWhetherLeadingTokens[3]{%
  \romannumeral\UD@CheckWhetherNull{#1}%
  {\expandafter\UD@stopromannumeral\UD@secondoftwo}%
  {%
    % Let's nest things into \UD@firstoftwo{...}{} to make sure they are nested in braces
    % and thus do not disturb when the test is carried out within \halign/\valign:
    \expandafter\UD@firstoftwo\expandafter{%
      \expandafter\expandafter\expandafter\UD@stopromannumeral
      \romannumeral
      \expandafter\UD@secondoftwo\string{\expandafter\UD@@CheckWhetherLeadingTokens#3{\relax}#1#2}{}}{}%
  }%
}%
\newcommand\UD@@CheckWhetherLeadingTokens[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\expandafter\expandafter\expandafter\UD@stopromannumeral
   \expandafter\expandafter\expandafter}%
  \expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% \UD@internaltokencheckdefiner{<internal token-check-macro>}%
%%                              {<token-sequence-gobble-macro>}%
%%                              {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything 
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%
%% Defines <token-sequence-gobble-macro> to remove <token sequence> which in the
%% token-stream must definitely follow the token <token-sequence-gobble-macro>.
%%-----------------------------------------------------------------------------
\newcommand\UD@internaltokencheckdefiner[3]{%
  \@ifdefinable#1{\long\def#1##1#3{{##1}}}%
  \@ifdefinable#2{\def#2#3{}}%
}%
%%=============================================================================
%% Define infrastructure for checking for a leading *:
%%=============================================================================
\UD@internaltokencheckdefiner{\UD@SnapToStar}{\UD@GobbleStar}{*}%
%
% Now you can check for a leading * via
%
% \UD@CheckWhetherLeadingTokens{<argument to check>}{*}{\UD@SnapToStar}%
%                              {<tokens in case <argument to check> has a leading *>}%
%                              {<tokens in case <argument to check> does not have a leading *>}%
%
% \UD@GobbleStar must be trailed by * and removes that *.
%%=============================================================================
%% Define infrastructure for checking for a leading sequence *<space token>:
%%=============================================================================
\UD@internaltokencheckdefiner{\UD@SnapToStarSpace}{\UD@GobbleStarSpace}{* }%
%
% Now you can check for a leading sequence *<space token>  via
%
% \UD@CheckWhetherLeadingTokens{<argument to check>}{* }{\UD@SnapToStarSpace}%
%                              {<tokens in case <argument to check> has a leading *<space token> >}%
%                              {<tokens in case <argument to check> does not have a leading *<space token> >}%
%
% \UD@GobbleStarSpace must be trailed by a sequence *<space token>
% and removes that sequence *<space token>.
%%=============================================================================
%% Check if first token of macro-argument is an asterisk:
%%=============================================================================
%%
%% \testast{<argument to check>}%
%%         {<tokens in case <argument to check> has a leading *>}%
%%         {<tokens in case <argument to check> does not have a leading *>}%
%%
%%  (I suggest naming the command \CheckWhetherLeadingAsterisk instead of 
%    \testast.)
%%
\newcommand\testast[1]{%
  \UD@CheckWhetherLeadingTokens{#1}{*}{\UD@SnapToStar}%
}%
%------------------------------------------------------------------------------

\makeatother

\documentclass{article}

\usepackage{getitems} %!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! \usepackage{amsmath} %!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

\makeatletter \NewEnviron{multi}[1][]{% \expandafter\gatheritems\expandafter{\BODY}% \loopthroughitemswithcommand{\findcorrect}% }{}% \newcommand\findcorrect[1]{% \UD@CheckWhetherLeadingTokens{#1}{}{\UD@SnapToStar}{% \expandafter\gdef\expandafter\NumberOfCorrectAnswer\expandafter{% \number\value{currentitemnumber}% }% \UD@CheckWhetherLeadingTokens{#1}{ }{\UD@SnapToStarSpace}{% \expandafter\gdef\expandafter\TextOfCorrectAnswer\expandafter{\UD@GobbleStarSpace#1}% }{% \expandafter\gdef\expandafter\TextOfCorrectAnswer\expandafter{\UD@GobbleStar#1}% }% }{}% }% \makeatother

\begin{document}

\verb|\testast{Word}{YES}{NO}|: \testast{Word}{YES}{NO}

\verb|\testast{Word}{YES}{NO}|: \testast{Word}{YES}{NO}

\begin{multi} Text---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item Answer---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item Another answer---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item* Correct---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \end{multi}

The number of the correct answer is: \NumberOfCorrectAnswer.

The text of the correct answer is: \TextOfCorrectAnswer.

\end{document}

enter image description here



If you need counting of your multi-environments and extracting answers etc as specified in your comment

In fact I was about to asking :) there is a counting running, so I need to extract the text of questions, the possible answers, and the correct one. In what is my attempt, the counter is numes, then I use \csname TEXT\roman{numes} for the text \csname POSS\roman{numes} for the number of possible answers, \csname ANSWER\roman{n}ES\roman{numes} for the nth possible answer, and \csname CORRECT\roman{numes} for the number of correct choice. Then I use such macros for formatting exams, so I need to use then say like \expandafter\def\myneededmacro\cnsame TEXT\roman{numes}\endcsname

, then you can do something like the following where I use \UD@CsNameToCsToken for avoiding having even longer \expandafter-chains for generating control-sequence-tokens from control-sequence-names:

\makeatletter    
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange, \UD@stopromannumeral,
%%    \UD@CsNameToCsToken, \UD@CheckWhetherNull, \UD@CheckWhetherLeadingTokens
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% Obtain control sequence token from name of control sequence name:
%%-----------------------------------------------------------------------------
%% \CsNameToCsToken<stuff not in braces>{NameOfCs}
%% ->  <stuff not in braces>\NameOfCs
%% (<stuff not in braces> may be empty.)
\@ifdefinable\UD@CsNameToCsToken{%
  \long\def\UD@CsNameToCsToken#1#{\romannumeral\UD@@CsNameToCsToken{#1}}%
}%
\newcommand\UD@@CsNameToCsToken[2]{%
  \expandafter\UD@Exchange\expandafter{\csname#2\endcsname}{\UD@stopromannumeral#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\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific 
%% token-sequence that does not contain explicit character tokens of 
%% category 1 or 2 or 6:
%%.............................................................................
%% \UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%%                              {<a <token sequence> without explicit 
%%                                character tokens of category 1 or 2
%%                                or 6>}%
%%                              {<internal token-check-macro>}%
%%                              {<tokens to be delivered in case
%%                                <argument which is to be checked> has
%%                                <token sequence> as leading tokens>}%
%%                              {<tokens to be delivered in case 
%%                                <argument which is to be checked>
%%                                does not have <token sequence> as
%%                                leading tokens>}%
\newcommand\UD@CheckWhetherLeadingTokens[3]{%
  \romannumeral\UD@CheckWhetherNull{#1}%
  {\expandafter\UD@stopromannumeral\UD@secondoftwo}%
  {%
    % Let's nest things into \UD@firstoftwo{...}{} to make sure they are nested in braces
    % and thus do not disturb when the test is carried out within \halign/\valign:
    \expandafter\UD@firstoftwo\expandafter{%
      \expandafter\expandafter\expandafter\UD@stopromannumeral
      \romannumeral
      \expandafter\UD@secondoftwo\string{\expandafter\UD@@CheckWhetherLeadingTokens#3{\relax}#1#2}{}}{}%
  }%
}%
\newcommand\UD@@CheckWhetherLeadingTokens[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\expandafter\expandafter\expandafter\UD@stopromannumeral
   \expandafter\expandafter\expandafter}%
  \expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% \UD@internaltokencheckdefiner{<internal token-check-macro>}%
%%                              {<token-sequence-gobble-macro>}%
%%                              {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything 
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%
%% Defines <token-sequence-gobble-macro> to remove <token sequence> which in the
%% token-stream must definitely follow the token <token-sequence-gobble-macro>.
%%-----------------------------------------------------------------------------
\newcommand\UD@internaltokencheckdefiner[3]{%
  \@ifdefinable#1{\long\def#1##1#3{{##1}}}%
  \@ifdefinable#2{\def#2#3{}}%
}%
%%=============================================================================
%% END OF PARAPHERNALIA
%%=============================================================================
%%=============================================================================
%% CHECKING FOR LEADING ASTERISK OR LEADING ASTERISK TRAILED BY AN EXPLICIT
%% SPACE TOKEN
%%=============================================================================
%% Define infrastructure for checking for a leading *:
%%-----------------------------------------------------------------------------
\UD@internaltokencheckdefiner{\UD@SnapToStar}{\UD@GobbleStar}{*}%
%
% Now you can check for a leading * via
%
% \UD@CheckWhetherLeadingTokens{<argument to check>}{*}{\UD@SnapToStar}%
%                              {<tokens in case <argument to check> has a leading *>}%
%                              {<tokens in case <argument to check> does not have a leading *>}%
%
% \UD@GobbleStar must be trailed by * and removes that *.
%%-----------------------------------------------------------------------------
%% Define infrastructure for checking for a leading sequence *<space token>:
%%-----------------------------------------------------------------------------
\UD@internaltokencheckdefiner{\UD@SnapToStarSpace}{\UD@GobbleStarSpace}{* }%
%
% Now you can check for a leading sequence *<space token>  via
%
% \UD@CheckWhetherLeadingTokens{<argument to check>}{* }{\UD@SnapToStarSpace}%
%                              {<tokens in case <argument to check> has a leading *<space token> >}%
%                              {<tokens in case <argument to check> does not have a leading *<space token> >}%
%
% \UD@GobbleStarSpace must be trailed by a sequence *<space token>
% and removes that sequence *<space token>.
%%=============================================================================
%% END OF CHECKING FOR LEADING ASTERISK OR LEADING ASTERISK TRAILED BY AN 
%% EXPLICIT SPACE TOKEN
%%=============================================================================
\makeatother

\documentclass{article}

\usepackage{getitems} %!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! \usepackage{amsmath} %!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

\makeatletter \newcounter{numes}% \NewEnviron{multi}{% \stepcounter{numes}% % Instead of counting and defining \NameOfThisMultiInstance from the counter, % you can have the multi-environment process a mandatory argument where the % user is to pass a unique name for the current instance of the environment % and define \NameOfThisMultiInstance from that. \expandafter\gatheritems\expandafter{\BODY}% \UD@CsNameToCsToken@ifdefinable{TEXT\roman{numes}}{% \UD@CsNameToCsToken \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter\gdef \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter{TEXT\roman{numes}}% \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter{% \gathereditem{0}% }% }% \UD@CsNameToCsToken@ifdefinable{POSS\roman{numes}}{% \UD@CsNameToCsToken \expandafter\gdef\expandafter{POSS\roman{numes}}\expandafter{% \number\value{numgathereditems}% }% }% \loopthroughitemswithcommand{\extractanswers}% }{}% \newcommand\extractanswers[1]{% \UD@CheckWhetherLeadingTokens{#1}{}{\UD@SnapToStar}{% \UD@CsNameToCsToken@ifdefinable{CORRECTNUM\roman{numes}}{% \UD@CsNameToCsToken \expandafter\gdef\expandafter{CORRECTNUM\roman{numes}}\expandafter{% \number\value{currentitemnumber}% }% }% \UD@CsNameToCsToken@ifdefinable{ANSWER\roman{currentitemnumber}ES\roman{numes}}{% \UD@CheckWhetherLeadingTokens{#1}{ }{\UD@SnapToStarSpace}{% \UD@Exchange{\expandafter{\UD@GobbleStarSpace#1}}% }{% \UD@Exchange{\expandafter{\UD@GobbleStar#1}}% }% {% \UD@CsNameToCsToken \expandafter\gdef\expandafter {ANSWER\roman{currentitemnumber}ES\roman{numes}}% }% }% \UD@CsNameToCsToken@ifdefinable{CORRECTTEXT\roman{numes}}{% \UD@CsNameToCsToken\UD@CsNameToCsToken \global\let{CORRECTTEXT\roman{numes}}={ANSWER\roman{currentitemnumber}ES\roman{numes}}% }% }{% \UD@CsNameToCsToken@ifdefinable{ANSWER\roman{currentitemnumber}ES\roman{numes}}{% \UD@CsNameToCsToken\gdef{ANSWER\roman{currentitemnumber}ES\roman{numes}}{#1}% }% }% }% \makeatother

\begin{document}

\begin{multi} Header---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item First answer/incorect---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item Second answer/incorect---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item* Third answer-correct---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item Fourth answer/incorect---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \end{multi}

\verb|\TEXTi| yields: \TEXTi.

\verb|\POSSi| yields: \POSSi.

\verb|\CORRECTNUMi| yields: \CORRECTNUMi.

\verb|\CORRECTTEXTi| yields: \CORRECTTEXTi

\verb|\ANSWERiESi| yields: \ANSWERiESi.

\verb|\ANSWERiiESi| yields: \ANSWERiiESi.

\verb|\ANSWERiiiESi| yields: \ANSWERiiiESi.

\verb|\ANSWERivESi| yields: \ANSWERivESi.

\end{document}

enter image description here

Ulrich Diez
  • 28,770
  • could you upgrade your code so that it extracts also the text of non-correct answers? – user126154 May 14 '22 at 18:24
  • In fact I was about to asking :) there is a counting running, so I need to extract the text of questions, the possible answers, and the correct one. In what is my attempt, the counter is numes, then I use \csname TEXT\roman{numes} for the text \csname POSS\roman{numes} for the number of possible answers, \csname ANSWER\roman{n}ES\roman{numes} for the nth possible answer, and \csname CORRECT\roman{numes} for the number of correct choice. Then I use such macros for formatting exams, so I need to use then say like \expandafter\def\myneededmacro\cnsame TEXT\roman{numes}\endcsname – user126154 May 14 '22 at 19:25
  • @user126154 I just edited this once more - in the last example I overlooked that three instead of two expansion-steps need to be triggered on \gathereditem{0}: 1. Yields \csname..\endcsname-expression. 2. Forms control-sequence-token from \csname..\endcsname-expression. 3. Yields toplevel-expansion of control-sequence-token. Sorry. I don't know what I was thinking. – Ulrich Diez May 14 '22 at 23:36
  • Ok, now I would like to have text and aswers with initial blank spaces removed :). I posted a separated question here https://tex.stackexchange.com/questions/644284/hot-to-remove-any-kind-of-spces-at-the-beginning-of-something because it may be of independent interest. I'm sure you know how to do! – user126154 May 15 '22 at 08:34
1

You might consider using zref for placing labels so that things can be referenced even before the environments were processed:

In this variant the multi-environment has a mandatory argument where with each instance of that environment the user must provide a unique name for that instance.

Macros
\TEXT{⟨name of multi instance⟩},
\POSS{⟨name of multi instance⟩},
\CORRECTNUM{⟨name of multi instance⟩},
\CORRECTTEXT{⟨name of multi instance⟩},
\ANSWER{⟨name of multi instance⟩}{⟨number of answert⟩}
are used for retrieving desired information.

If you do this, like with any cross-referencing-mechanism you need at least two latex-runs until everything matches out.

\makeatletter
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange, \UD@PassFirstToSecond,
%%    \UD@stopromannumeral, \UD@CheckWhetherNull, \UD@CheckWhetherLeadingTokens
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% 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\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific 
%% token-sequence that does not contain explicit character tokens of 
%% category 1 or 2 or 6:
%%.............................................................................
%% \UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%%                              {<a <token sequence> without explicit 
%%                                character tokens of category 1 or 2
%%                                or 6>}%
%%                              {<internal token-check-macro>}%
%%                              {<tokens to be delivered in case
%%                                <argument which is to be checked> has
%%                                <token sequence> as leading tokens>}%
%%                              {<tokens to be delivered in case 
%%                                <argument which is to be checked>
%%                                does not have <token sequence> as
%%                                leading tokens>}%
\newcommand\UD@CheckWhetherLeadingTokens[3]{%
  \romannumeral\UD@CheckWhetherNull{#1}%
  {\expandafter\UD@stopromannumeral\UD@secondoftwo}%
  {%
    % Let's nest things into \UD@firstoftwo{...}{} to make sure they are nested in braces
    % and thus do not disturb when the test is carried out within \halign/\valign:
    \expandafter\UD@firstoftwo\expandafter{%
      \expandafter\expandafter\expandafter\UD@stopromannumeral
      \romannumeral
      \expandafter\UD@secondoftwo\string{\expandafter\UD@@CheckWhetherLeadingTokens#3{\relax}#1#2}{}}{}%
  }%
}%
\newcommand\UD@@CheckWhetherLeadingTokens[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\expandafter\expandafter\expandafter\UD@stopromannumeral
   \expandafter\expandafter\expandafter}%
  \expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% \UD@internaltokencheckdefiner{<internal token-check-macro>}%
%%                              {<token-sequence-gobble-macro>}%
%%                              {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything 
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%
%% Defines <token-sequence-gobble-macro> to remove <token sequence> which in the
%% token-stream must definitely follow the token <token-sequence-gobble-macro>.
%%-----------------------------------------------------------------------------
\newcommand\UD@internaltokencheckdefiner[3]{%
  \@ifdefinable#1{\long\def#1##1#3{{##1}}}%
  \@ifdefinable#2{\def#2#3{}}%
}%
%%=============================================================================
%% END OF PARAPHERNALIA
%%=============================================================================
%%=============================================================================
%% CHECKING FOR LEADING ASTERISK OR LEADING ASTERISK TRAILED BY AN EXPLICIT
%% SPACE TOKEN
%%=============================================================================
%% Define infrastructure for checking for a leading *:
%%-----------------------------------------------------------------------------
\UD@internaltokencheckdefiner{\UD@SnapToStar}{\UD@GobbleStar}{*}%
%
% Now you can check for a leading * via
%
% \UD@CheckWhetherLeadingTokens{<argument to check>}{*}{\UD@SnapToStar}%
%                              {<tokens in case <argument to check> has a leading *>}%
%                              {<tokens in case <argument to check> does not have a leading *>}%
%
% \UD@GobbleStar must be trailed by * and removes that *.
%%-----------------------------------------------------------------------------
%% Define infrastructure for checking for a leading sequence *<space token>:
%%-----------------------------------------------------------------------------
\UD@internaltokencheckdefiner{\UD@SnapToStarSpace}{\UD@GobbleStarSpace}{* }%
%
% Now you can check for a leading sequence *<space token>  via
%
% \UD@CheckWhetherLeadingTokens{<argument to check>}{* }{\UD@SnapToStarSpace}%
%                              {<tokens in case <argument to check> has a leading *<space token> >}%
%                              {<tokens in case <argument to check> does not have a leading *<space token> >}%
%
% \UD@GobbleStarSpace must be trailed by a sequence *<space token>
% and removes that sequence *<space token>.
%%=============================================================================
%% END OF CHECKING FOR LEADING ASTERISK OR LEADING ASTERISK TRAILED BY AN 
%% EXPLICIT SPACE TOKEN
%%=============================================================================
\makeatother

\documentclass{article}

\usepackage{getitems} \usepackage{amsmath} \makeatletter \usepackage{zref}% \zref@newprop{Multi}{}% \newcommand\TEXT[1]{\zref@extract{MULTI_TEXT_{#1}}{Multi}}% \newcommand\POSS[1]{\zref@extract{MULTI_POSS_{#1}}{Multi}}% \newcommand\CORRECTNUM[1]{\zref@extract{MULTI_CORRECTNUM_{#1}}{Multi}}% \newcommand\CORRECTTEXT[1]{\zref@extract{MULTI_CORRECTTEXT_{#1}}{Multi}}% \newcommand\ANSWER[2]{\zref@extract{MULTI_ANSWER_{#1}{#2}}{Multi}}% \newcommand\ThisMultiName{}% \NewEnviron{multi}[1]{% \def\ThisMultiName{#1}% \expandafter\gatheritems\expandafter{\BODY}% \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter\UD@PassFirstToSecond \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter{\gathereditem{0}}% {\zref@setcurrent{Multi}}% \zref@labelbyprops{MULTI_TEXT_{\ThisMultiName}}{Multi}% \expandafter\UD@PassFirstToSecond \expandafter{\number\value{numgathereditems}}% {\zref@setcurrent{Multi}}% \zref@labelbyprops{MULTI_POSS_{\ThisMultiName}}{Multi}% \loopthroughitemswithcommand{\extractanswers}% }{}% \newcommand\extractanswers[1]{% \UD@CheckWhetherLeadingTokens{#1}{}{\UD@SnapToStar}{% \expandafter\UD@PassFirstToSecond \expandafter{\number\value{currentitemnumber}}% {\zref@setcurrent{Multi}}% \zref@labelbyprops{MULTI_CORRECTNUM_{\ThisMultiName}}{Multi}% \expandafter\UD@PassFirstToSecond \expandafter{% \romannumeral \UD@CheckWhetherLeadingTokens{#1}{ }{\UD@SnapToStarSpace}% {\expandafter\UD@stopromannumeral\UD@GobbleStarSpace}% {\expandafter\UD@stopromannumeral\UD@GobbleStar}#1% }% {\zref@setcurrent{Multi}}% \zref@labelbyprops{MULTI_ANSWER_{\ThisMultiName}{\arabic{currentitemnumber}}}{Multi}% \zref@labelbyprops{MULTI_CORRECTTEXT_{\ThisMultiName}}{Multi}% }{% \zref@setcurrent{Multi}{#1}% \zref@labelbyprops{MULTI_ANSWER_{\ThisMultiName}{\arabic{currentitemnumber}}}{Multi}% }% }% \makeatother

\begin{document}

\verb|\TEXT{NameOfThisMulti}| yields: \TEXT{NameOfThisMulti}.

\verb|\POSS{NameOfThisMulti}| yields: \POSS{NameOfThisMulti}.

\verb|\CORRECTNUM{NameOfThisMulti}| yields: \CORRECTNUM{NameOfThisMulti}.

\verb|\CORRECTTEXT{NameOfThisMulti}| yields: \CORRECTTEXT{NameOfThisMulti}.

\verb|\ANSWER{NameOfThisMulti}{1}| yields: \ANSWER{NameOfThisMulti}{1}.

\verb|\ANSWER{NameOfThisMulti}{2}| yields: \ANSWER{NameOfThisMulti}{2}.

\verb|\ANSWER{NameOfThisMulti}{3}| yields: \ANSWER{NameOfThisMulti}{3}.

\verb|\ANSWER{NameOfThisMulti}{4}| yields: \ANSWER{NameOfThisMulti}{4}.

\begin{multi}{NameOfThisMulti}% Header---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item First answer/incorect---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item Second answer/incorect---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item* Third answer-correct---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \item Fourth answer/incorect---$\begin{pmatrix} a&b\c&d\end{pmatrix}$ \end{multi}

\end{document}

enter image description here

Ulrich Diez
  • 28,770