3

Here is how I do to work with unbounded number of arguments of a macro. Is there a better way to do that ?

\documentclass[12pt,a4paper]{article}

\usepackage{ifmtarg}
\usepackage{nicematrix}

\makeatletter
    \def\backify#1|#2\@nil{%
        \@ifmtarg{#2}{%
            #1%
        }{%
            #1 \\ \backify#2\@nil%
        }%
    }

    \newcommand\vcoord[1]{%
        \begin{pmatrix}
            \backify#1|\@nil %
        \end{pmatrix}%
    }
\makeatother

\begin{document}

$\vcoord{3 | -4 | 0}$

\end{document}
projetmbc
  • 13,315
  • 2
    There are some ready-made solutions in etoolbox (look for \DeclareListParser and \forcsvlist) and of course expl3/LaTeX3 has a lot of list parsing/splitting functions going on. – moewe Feb 17 '19 at 07:43
  • We the ready-to-use solutions, can I transform one list sperated with one symbol to the same list separated with another ? – projetmbc Feb 17 '19 at 07:45
  • this https://tex.stackexchange.com/questions/12810/how-do-i-split-a-string/12811 can help you maybe – Anton Lioznov Feb 17 '19 at 09:20
  • 1
    It depends on whether you wish to process the arguments successively, e.g., one by one, or simultaneously. Seems you are interested in processing the arguments successively. Nonetheless the discussion How to define a command that takes more than 9 arguments might be of interest to you. – Ulrich Diez Feb 17 '19 at 13:00
  • 1
    Your macro \backify's first arg is delimited by | and its second arg is delimited by \@nil. If a delimited arg is nested in braces entirely, these braces will be stripped off. Your \vcoord-macro processes a list of |-delimited arguments. With all elements except the last one, brace-stripping can happen only once, while with the last element brace-stripping can happen twice. As it is relied on \@nil not being provided by the user, within \vcoord the sequence |{\@nil}|\@nil could be attached and instead of checking on the emptiness of #2 one could check whether #1=\@nil. – Ulrich Diez Feb 17 '19 at 13:14
  • 1
    Your \vcoord-macro seems to be just an example. It has nice arguments. You can do it with #1\\\backify as long as cases are excluded where #1 consists of tokens that erroneously "eat" the trailing \\\backify and this way terminate the loop prematurely. – Ulrich Diez Feb 17 '19 at 13:23
  • @UlrichDiez You're right but in (La)TeX I'm just a padawan. I think that I will use the egreg solution. – projetmbc Feb 20 '19 at 12:47
  • @projetmbc As a simple provincial, I'm not very familiar with the Star Wars milieu and therefore had to do a google-search on the word "padawan". :-) I think there is no need to explain oneself. ;-) Do whatever you think does fit your needs the best. That's what everyone does and that's the way things are going on StackExchange: One asks questions. From the answers and comments one chooses what one thinks does fit one's needs the best, or one takes the answers and comments as a source of inspiration for cobbling something together on one's own. ;-) – Ulrich Diez Feb 20 '19 at 13:06
  • @projetmbc As on the one hand, you call yourself "Padawan", and, on the other hand, you write that you wish to stick to egreg's solution, I would like to mention that orienting yourself towards egreg's answers is not a bad strategy at all: Studying egreg's answers helps a lot. Every time I visit TeX-LaTeX-StackExchange, I learn from his answers. – Ulrich Diez Feb 20 '19 at 23:06
  • @UlrichDiez Me too I already know egreg and he is like my Obi Wan Kenobi. ;-) Sorry for this geek culture. ;-) – projetmbc Feb 21 '19 at 13:09

3 Answers3

5

Using expl3 (which is loaded by xparse) you can use the built-in sequence type. The following defines your \vcoord using only built-in functions. The result is not expandable. It also adds two macros, \readsequence that sets up a sequence variable (unexpandable), and \usesequence which expands to the sequence with each sequence element separated by its argument (expandable). You can look at interface3 for the documentation of the available functions in expl3.

\documentclass[]{article}

\usepackage{amsmath}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l__projetmbc_seq
\NewDocumentCommand \readsequence { +m +m }
  {
    \seq_set_split:Nnn \l__projetmbc_seq { #1 } { #2 }
  }
\NewExpandableDocumentCommand \usesequence { +m }
  {
    \seq_use:Nnnn \l__projetmbc_seq { #1 } { #1 } { #1 }
  }
\NewDocumentCommand \vcoord { m }
  {
    \group_begin:
    \seq_set_split:Nnn \l__projetmbc_seq { | } { #1 }
    \begin { pmatrix }
      \seq_use:Nnnn \l__projetmbc_seq { \\ } { \\ } { \\ }
    \end { pmatrix }
    \group_end:
  }
\ExplSyntaxOff

\begin{document}
\readsequence{|}{a|b|c|d|e}
\[
  \begin{pmatrix}
    \usesequence{\\}
  \end{pmatrix}
\]

\[
  \vcoord{3|-4|0}
\]
\end{document}
Skillmon
  • 60,462
4

Not sure about best practice, but you can simplify the definition somewhat:

\documentclass[12pt,a4paper]{article}

\usepackage{amsmath}


\long\def\backify#1|{#1\backify\\}
\def\endbackify#1#2{}

    \newcommand\vcoord[1]{%
        \begin{pmatrix}
            \backify#1|\endbackify|%
        \end{pmatrix}%
    }


\begin{document}

$\vcoord{3 | -4 | 0}$

\end{document}
David Carlisle
  • 757,742
3

I propose a different way to cope with what you seem to be doing.

\documentclass[12pt,a4paper]{article}

\usepackage{xparse}
\usepackage{amsmath}

\ExplSyntaxOn

% a general purpose macro for defining other macros
\NewDocumentCommand{\makemultiargument}{mmmmm}
 {
  \projetmbc_multiarg:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 }
 }

% allocate a private variable
\seq_new:N \l__projetmbc_generic_seq

% the internal version of the general purpose macro
\cs_new_protected:Nn \projetmbc_multiarg:nnnnn
 {% #1 = separator
  % #2 = multiargument
  % #3 = code before
  % #4 = code between
  % #5 = code after

  % a group allows nesting
  \group_begin:
  % split the multiargument into parts
  \seq_set_split:Nnn \l__projetmbc_generic_seq { #1 } { #2 }
  % execute the <code before>
  #3
  % deliver the items, with the chosen material between them
  \seq_use:Nn \l__projetmbc_generic_seq { #4 }
  % execute the <code after>
  #5
  % end the group started at the beginning
  \group_end:
 }

\ExplSyntaxOff

% separator: |; before: \begin{pmatrix}; between: \\, after: \end{pmatrix}
\newcommand{\vcoord}[1]{%
  \makemultiargument{|}{#1}{\begin{pmatrix}}{\\}{\end{pmatrix}}%
 }

\begin{document}

$\vcoord{3 | \vcoord{-4 | -3 } | 0}$ 

\end{document}

enter image description here

It is possible to add formatting to each entry, with a trailing optional argument (without it the macro is the same as in the previous version).

\documentclass[12pt,a4paper]{article}

\usepackage{xparse}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\makemultiargument}{mmmmmo}
 {
  \projetmbc_multiarg:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { #6 }
 }

\seq_new:N \l__projetmbc_generic_seq

\cs_new_protected:Nn \projetmbc_multiarg:nnnnnn
 {% #1 = separator
  % #2 = multiargument
  % #3 = code before
  % #4 = code between
  % #5 = code after
  % #6 = ornament to items

  % allow nesting
  \group_begin:
  % split the multiargument
  \seq_set_split:Nnn \l__projetmbc_generic_seq { #1 } { #2 }
  \tl_if_novalue:nF { #6 }
   {
    \seq_set_eq:NN \l__projetmbc_temp_seq \l__projetmbc_generic_seq
    \seq_set_map:NNn \l__projetmbc_generic_seq \l__projetmbc_generic_seq { #6 }
   }
  #3
  \seq_use:Nn \l__projetmbc_generic_seq { #4 }
  #5
  \group_end:
 }

\ExplSyntaxOff

\NewDocumentCommand{\vcoord}{m}
 {
  \makemultiargument{|}{#1}{\begin{pmatrix}}{\\}{\end{pmatrix}}
 }

\NewDocumentCommand{\pboxed}{m}{\boxed{#1}}

\begin{document}

$\vcoord{3 | \vcoord{-4 | -3 } | 0}$

$\makemultiargument{|}{-4 | -3  | 0}{\begin{pmatrix}}{\\}{\end{pmatrix}}[\pboxed{#1}]$

\end{document}

Beware that macros in the trailing argument have to be either fully expandable or protected (which is why I defined \pboxed; the standard \boxed would not fail, but just by chance).

enter image description here

egreg
  • 1,121,712
  • Thanks a lot for the comment. I have a little question about the meanings of mmmmm and the nnnnn. What is for you the best place where to learn expl3 features ? – projetmbc Feb 20 '19 at 13:02
  • @projetmbc texdoc interface3 for the available functions and a bit about naming conventions, texdoc expl3 for naming conventions and additional information about LaTeX3. There is also texdoc ltx3info and others. Or take a look at the available pdfs on CTAN: https://ctan.org/pkg/l3kernel – Skillmon Feb 20 '19 at 14:03
  • @egreg Is there a way to give a 6th argument that will be a command to apply on each item of the sequence \seq_use:Nn \l__projetmbc_generic_seq { #4 } ? – projetmbc Feb 21 '19 at 14:33
  • @projetmbc Added; not too difficult, after all. – egreg Feb 21 '19 at 16:55
  • Except for little padawan like me. ;-) Thanks a lot ! – projetmbc Feb 21 '19 at 18:45