5

I'm trying to create a command, called \newcscommand, that lets me define commands with values separated by commas.

Here's what I have so far

\documentclass{article}
\usepackage{xparse}

\newcommand{\newcscommand}[3]{
  \NewDocumentCommand{ #1 }{ >{\SplitArgument{#2 - 1}{,}}m }{\csname aux\endcsname##1} % the auxiliary command should be named 'auxtest' instead of just aux
  \newcommand{\aux}[#2]{#3} % same here
}

\newcscommand{\test}{3}{#1 is #2 a #3.}
\begin{document}
\test{This, just, test}
\end{document}

I use an auxiliary command to split the comma separated list, which should be called 'aux + the name of the command', however I couldn't get it to work so I left it as 'aux' in the MWE, which is if of course wrong because if I call newcscommand twice I'll get an error.

I know that I have to use csname and endcsname somehow, but I haven't figured it out.

How can I get this to work? Is there a totally different and better way to do this that I don't know about?

3

Your idea is good, but proper expl3 programming is better:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newcscommand}{mO{0}m}
 {
  \NewDocumentCommand{#1}{ >{\SplitArgument{#2-1}{,}}m }
    {
     \use:c { __noibe_\cs_to_str:N #1:\prg_replicate:nn{#2}{n} } ##1
    }
  \cs_new:cn { __noibe_\cs_to_str:N #1:\prg_replicate:nn{#2}{n} } { #3 }
 }

\ExplSyntaxOff

\newcscommand{\test}[3]{#1 is #2 a #3.}

\begin{document}

\test{This, just, test}

\end{document}

Note that the syntax of \newcscommand is similar to \newcommand.

The trick is indeed to create a macro with the correct number of arguments in its signature.

A variant that avoids calling \use:c and \prg_replicate:nn each time \test is executed, because the control sequence name is built at definition time thanks to \exp_not:c.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newcscommand}{mO{0}m}
 {
  \exp_args:Nnne \NewDocumentCommand{#1}{ >{\SplitArgument{#2-1}{,}}m }
   {
    \exp_not:c { __noibe_\cs_to_str:N #1:\prg_replicate:nn{#2}{n} } ##1
   }
  \cs_new:cn { __noibe_\cs_to_str:N #1:\prg_replicate:nn{#2}{n} } { #3 }
}
\exp_args_generate:n { nne }

\ExplSyntaxOff

\newcscommand{\test}[3]{#1 is #2 a #3.}

\begin{document}

\test{This, just, test}

\end{document}
  • Thanks for the feedback. How can I extend this to a renewcscommand command? I tried simply copy-pasting it, with the substitution \exp_args:Nnne \NewDocumentCommand -> \exp_args:Nnne \RenewDocumentCommand, but that didn't work too well. – noibe Nov 2 at 0:13
  • @noibe Change also \cs_new:cn into \cs_set:cn – egreg Nov 2 at 0:24
3

This doesn't check for list length, but that can be done. Likewise, the arguments can be added to a \foreachitem loop.

\documentclass{article}
\usepackage{listofitems}
\newcommand\test[1]{%
  \readlist*\mylist{#1}%
  \mylist[1] is \mylist[2] a \mylist[3].
}
\begin{document}
\test{This, just, test}
\end{document}

enter image description here

Here's an example where number of arguments may vary, yet be accounted for:

\documentclass{article}
\usepackage{listofitems}
\newcommand\test[1]{%
  \readlist*\mylist{#1}%
  There are \mylistlen{} arguments:
  \foreachitem \z \in \mylist[]{\ifnum\zcnt=1\relax\else, \fi(\zcnt) \z}.
}
\begin{document}
\test{This, just, test}

\test{This, just, test, today, Hallelujah}
\end{document}

enter image description here

3

I figured it out eventually:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\newcommand{\newcscommand}[3]{
  \NewDocumentCommand{ #1 }{ >{\SplitArgument{#2 - 1}{,}}m }{\csname aux\cs_to_str:N #1\endcsname##1}
  \expandafter\newcommand\csname aux\cs_to_str:N #1\endcsname[#2]{#3}
}

\ExplSyntaxOff

\newcscommand{\test}{3}{#1 is #2 a #3.}
\begin{document}
\test{This, just, test}
\end{document}

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.