TransWikia.com

How to turn string into command?

TeX - LaTeX Asked on October 4, 2021

I have commands called cta, ctb, ctc, ctd.

I’d like to call these commands from within a loop, as follows:

foreach i in {a,b,c,d}{
% this is where I want to call the command 
}

How can I achieve this?

3 Answers

The TeX primitives csname...endcsname allow to construct macro names.

documentclass{article}

usepackage{tikz}

newcommand*{cta}{A}
newcommand*{ctb}{BB}
newcommand*{ctc}{CCC}
newcommand*{ctd}{DDDD}

begin{document}

foreach i in {a,b,c,d}{The content of texttt{expandafterstringcsname ctiendcsname} is csname ctiendcsname.par}

end{document}

enter image description here

When TeX encounters

csname ctiendcsname

it expands i (and it keeps expanding) until only character tokens are obtained, and builds a control sequence with the corresponding "string". (An error is thrown if the expansion produces a non-character token.)

Correct answer by campa on October 4, 2021

A fairly general loop:

documentclass{article}
usepackage{xparse}

ExplSyntaxOn

NewDocumentCommand{loopvar}{m +O{} m +O{}}
 {
  clist_map_inline:nn { #3 } { #2 use:c { #1##1 } #4 }
 }

ExplSyntaxOff

newcommand{cta}{texttt{stringcta}}
newcommand{ctb}{texttt{stringctb}}
newcommand{ctc}{texttt{stringctc}}
newcommand{ctd}{texttt{stringctd}}

begin{document}

loopvar{ct}{a,b,c,d}

loopvar{ct}[This is ]{a,b,c}[par]

end{document}

The first mandatory argument is the common part, the second mandatory argument is the list of strings to append; the first optional argument is a “prefix” to add before the macro, the traling one is the “postfix”.

Explanation: use:c builds a control sequence name from its argument and is essentially csname...endcsname in disguise; clist_map_inline:nn maps the comma separated list executing for each item the code specified in the second argument (#1 stands for the current item, but here we need to use ##1 because we're defining a macro).

enter image description here

Answered by egreg on October 4, 2021

As in TeX everything is about tokens that might be expandable, you are faced with the question about the order in time in which expansion of cta, ctb, ctc, ctd shall take place.

Case 1:

Is the loop to deliver the entire token-sequence ctactbctcctd ?

(In case cta is a macro that processes three non-delimited arguments, its first argument is the token ctb, its second argument is the token ctc and its third argument is the token ctd.)

Case 2:

Is the token cta to be produced and expanded totally and carried out completely in the first iteration, then the token ctb to be produced and expanded totally and carried out completely in the second iteration, then the token ctc to be produced and expanded totally and carried out completely in the third iteration, then the token ctd to be produced and expanded totally and carried out completely in the fourth iteration?

How to do the second case has already been shown by campa and egreg.

So let's focus on the first case:

You could use a scratch-macro for accumulating tokens:

documentclass{article}

usepackage{tikz}

newcommand*{cta}[3]{%
  noindent
  texttt{stringcta}'s first argument is: texttt{string#1}%
  texttt{stringcta}'s second argument is: texttt{string#2}%
  texttt{stringcta}'s third argument is: texttt{string#3}%
  
  bigskip

  #1#2#3%
}
newcommand*{ctb}[2]{%
  noindent
  texttt{stringctb}'s first argument is: texttt{string#1}%
  texttt{stringctb}'s second argument is: texttt{string#2}%

  bigskip

  #1#2%
}
newcommand*{ctc}[1]{%
  noindent
  texttt{stringctc}'s first argument is: texttt{string#1}%

  bigskip

  #1%
}
newcommand*{ctd}{%
  noindent
  texttt{stringctd} does not process arguments.%
}

newcommandscratchmacro{}%

begin{document}

defscratchmacro{}
foreach i in {a,b,c,d}{%
  csname g@addto@macro%
           expandafterendcsname
           expandafter{%
           expandafterscratchmacro
           expandafter}%
           expandafter{%
             csname ctiendcsname
          }%
}%

noindent
texttt{stringscratchmacro: meaningscratchmacro}

bigskip

scratchmacro

end{document}

enter image description here

If you wish a fully expandable loop, then you are faced with the task of expandable comma-list-parsing.

In this case you might be interested in the answers to the question newcommand with many arguments.

If you wish a fully expandable loop, but can make it with a list of non-delimited arguments instead of a comma-list, i.e., something like {a}{b}{c}{d} instead of a,b,c,d, then you are faced with the task of expandable argument-list-parsing.

In this case you might be interested in some of the answers to the question defining a new command with variable name in a loop.


Another approach could be:

documentclass{article}

makeatletter
newcommandUD@exchange[2]{#2#1}%
newcommandnameloop{romannumeral0UD@innernameloop}%
newcommandUD@innernameloop[3]{%
  ifxrelax#3expandafter@firstoftwoelseexpandafter@secondoftwofi
  { #2}{%
    expandafterUD@exchange
    expandafter{%
    expandafter{%
      romannumeral0%
      expandafterUD@exchangeexpandafter{%
        csname#1#3endcsname
      }{ #2}%
    }}{%
      UD@innernameloop{#1}%
    }%
  }%
}%
makeatother

expandafterexpandafterexpandafterdef
expandafterexpandafterexpandafterscratchmacro
expandafterexpandafterexpandafter{%
  nameloop{ct}{Tokens in front}{a}{b}{c}{d}{relax}%
}%

begin{document}

texttt{stringscratchmacro: meaningscratchmacro}

end{document}

enter image description here

Answered by Ulrich Diez on October 4, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP