8

I have a mathematical symbol with 6 labels but there are multiple conventions for displaying such a symbol. One way would be [F^{abc}_d]_{ef} but other people use, e.g., [F^{abc}_d]^{e}_{f} or other forms. Since I'm at the start of writing a thesis I'd prefer not to make an absolute choice and decided to define a command with 6 labels as input such as

\newcommand{\F}[6]{[F^{{#1} {#2} {#3}}_{#4}]^{#5}_{#6}}

but then I have to type \F{a}{b}{c}{d}{e}{f} which is a bit cumbersome. Is there any way that I could call the new command using a comma separated list, e.g. \F{a,b,c,d,e,f}, instead of the standard way??

Gert
  • 182
  • Write a second macro, which process your short version ... – MS-SPO Mar 09 '22 at 13:17
  • I haven't done this myself, but I have the impression that using a keyval package would make the most sense since it allows you to name the parameters and define default values, which makes writing macros a lot easier. Here is a long list of these packages: https://tex.stackexchange.com/questions/26771/a-big-list-of-every-keyval-package Moreover, this might be helpful in finding the correct package for your use case: https://tex.stackexchange.com/questions/292869/reason-not-to-use-a-specific-key-val-package – Dave Mar 09 '22 at 13:21
  • there are various options to handle a comma list, e.g. with expl3 but also with etoolbox. – Ulrike Fischer Mar 09 '22 at 13:26
  • @MS-SPO Would you like to elaborate on how to do that? I'm quite new to macros myself... – Gert Mar 09 '22 at 13:36
  • Can the values of labels (a, ..., f) contain a comma? – Paul Gaborit Mar 09 '22 at 16:34

4 Answers4

7

The listofitems package can parse lists, using a comma (default) or other designated tokens.

Note that your list will need at least 5 commas, or an error will occur when calling \Fvar[6].

\documentclass{article}
\usepackage{listofitems}
\newcommand{\F}[1]{%
  \readlist*\Fvar{#1}%
  [F^{{\Fvar[1]} {\Fvar[2]} {\Fvar[3]}}_{\Fvar[4]}]^{\Fvar[5]}_{\Fvar[6]}}
\begin{document}
\begin{equation}
\F{a,b,c,d,e,f}
\end{equation}
\end{document}

enter image description here

  • Thank you so much for the response! I do get an error when using 10 parameters though. I read the documentation of listofitems but it doesn't give any indication as to why this error occurs. – Gert Sep 19 '22 at 15:19
  • @Gert \newcommand can take no more than 9 parameters...this is a limitation intrinsic to TeX. However, for the approach detailed in this answer, there should not be a problem if the list exceeds 9 items...when doing so, \Fvar[10] would access the 10th item of this list. – Steven B. Segletes Sep 19 '22 at 23:03
  • thank you very much. Somehow it does complain about the 10. I did `solve' the problem by using \Fvar[-1], though, which gives me the feeling the problem has more to do with the package than with \newcommand – Gert Sep 20 '22 at 08:22
5

you can try

\documentclass{article}
\begin{document}
  \def\F(#1,#2,#3,#4,#5,#6){[F^{{#1}{#2}{#3}}_{#4}]^{#5}_{#6}}

$\F(a,b,c,d,e,f)$ \end{document}

ljguo
  • 1,213
  • 1
  • 4
  • 12
4

You can use expl3's \clist_map_function:nN or the like for mapping all items of a comma-separated list to a function which appends its argument to a token-list, nested in braces.

Then you can use \tl_count:V for counting the brace-nested arguments. If there are six of them, proceed by prepending to the token-list the call to the underlying macro for processing six arguments. If there are not six of them, raise an error.

A problem is that \clist_map_function:nN silently skips/discards blank comma-list items. This can be prevented, e.g., by regexp-replacing in the comma-list any number of horizontal spaces ocurring between commas by the same number of horizontal spaces, but nested in braces. In order to forbid a trailing comma in the comma-list the same can be done with any number of horizontal spaces ocurring between the last comma and the end of the comma-list.

\ExplSyntaxOn
\cs_new:Nn \__MyStuff_Replaceblankitems: { 
  \exp_args:NnV \regex_match:nnTF {\,([\s])*\,} \l_tmpb_tl
  { \regex_replace_all:nnN {\,([\s])*\,} {\,\{\1\}\,} \l_tmpb_tl \__MyStuff_Replaceblankitems: } 
  { \regex_replace_all:nnN {\,([\s])*\z} {\,\{\1\}} \l_tmpb_tl  }
}
\cs_new_protected:Npn \F #1 {
  \tl_set:Nn \l_tmpb_tl {#1}
  % nest blank items of the comma-list between braces so that \clist_map_function:nN will not discard them.
  \__MyStuff_Replaceblankitems:
  %\tl_show:N \l_tmpb_tl
  \tl_clear:N \l_tmpa_tl
  \exp_args:NV \clist_map_function:nN \l_tmpb_tl {\__MyStuff_PutRightTo_l_tempa_tl:n }
  \int_compare:nNnTF {\tl_count:V {\l_tmpa_tl}} = {6}
                     {\tl_put_left:Nn \l_tmpa_tl {\__MyStuff_F:nnnnnn} \tl_use:N \l_tmpa_tl } 
                     {\msg_error:nnn  { MyStuff } { not-six-items } { \F }}
  \tl_clear:N \l_tmpa_tl
  \tl_clear:N \l_tmpb_tl
}
\cs_new:Nn \__MyStuff_F:nnnnnn {
  [F\c_math_superscript_token{{#1}{#2}{#3}}
  \c_math_subscript_token{#4}]
  \c_math_superscript_token{#5}
  \c_math_subscript_token{#6}
}
\cs_new:Nn  \__MyStuff_PutRightTo_l_tempa_tl:n {\tl_put_right:Nn \l_tmpa_tl {{#1}}}
\msg_new:nnn { MyStuff }
  { not-six-items }
  { \token_to_str:N #1's~argument~does~not~hold~a~comma-list~with~six~components.}
\prop_gput:Nnn \g_msg_module_type_prop { MyStuff } {}
\prop_gput:Nnx \g_msg_module_name_prop { MyStuff } {\jobname.tex~(main)}
\ExplSyntaxOff

\documentclass{article}

\begin{document}

[\F{a,b,c,d,e,f}]

% These raise errors:

%[\F{a,b,c,d,e,f, }]

%[\F{a,b,c,d,e,f,}]

%[\F{a,b,c,d,e, ,,f}]

%[\F{a,b,c,d,e,f,g}]

\end{document}

enter image description here

Werner
  • 603,163
Ulrich Diez
  • 28,770
3

You can use expl3 and extract the items from the list by number.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\F}{m} { \int_compare:nF { \clist_count:n { #1 } = 6 } { \ERROR } [F \sp { \clist_item:nn {#1}{1} \clist_item:nn {#1}{2} \clist_item:nn {#1}{3} } \sb { \clist_item:nn {#1}{4} } ] \sp { \clist_item:nn {#1}{5} } \sb { \clist_item:nn {#1}{6} } }

\ExplSyntaxOff

\begin{document}

$\F{a,b,c,d,e,f}$

\end{document}

enter image description here

A different (and more efficient) strategy would be to replace {a,b,c,d,e,f} with {a}{b}{c}{d}{e}{f}, which can be done in the following way: with \clist_map_function:nN we can use a function that braces the item; so from a,b,c,d,e,f we can expand the mapping at once and so \gert_f:n will be called as

\gert_f:n { {a}{b}{c}{d}{e}{f} }

and it can pass the argument to the “internal” six argument function.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\F}{m} { \int_compare:nTF { \clist_count:n { #1 } = 6 } { \gert_f:e { \clist_map_function:nN { #1 } __gert_f_brace:n } } { \ERROR } }

\cs_new_protected:Nn \gert_f:n { __gert_f:nnnnnn #1 } \cs_generate_variant:Nn \gert_f:n { e }

\cs_new_protected:Nn __gert_f:nnnnnn { [F \sp { #1 #2 #3 } \sb { #4 }] \sp { #5 } \sb { #6 } }

\cs_new:Nn __gert_f_brace:n { {#1} }

\ExplSyntaxOff

\begin{document}

$\F{a,b,c,d,e,f}$

\end{document}

In either case you have just one place where applying changes if a different output style is decided upon.

The error checking is just hinted at and something more detailed can be added easily.

If you plan to have empty items, then you need to split the list into a sequence, so empty items will not be discarded.

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\F}{m} { \seq_set_split:Nnn \l__gert_f_seq { , } { #1 } \int_compare:nTF { \seq_count:N \l__gert_f_seq = 6 } { \gert_f:e { \seq_map_function:NN \l__gert_f_seq __gert_f_brace:n } } { \ERROR } }

\seq_new:N \l__gert_f_seq

\cs_new_protected:Nn \gert_f:n { __gert_f:nnnnnn #1 } \cs_generate_variant:Nn \gert_f:n { e }

\cs_new_protected:Nn __gert_f:nnnnnn { [F \sp { #1 #2 #3 } \sb { #4 }] \sp { #5 } \sb { #6 } }

\cs_new:Nn __gert_f_brace:n { {#1} }

\ExplSyntaxOff

\begin{document}

$\F{a,b,c,d,e,f}$

$\F{a,,c,d,,f}$

\end{document}

enter image description here

egreg
  • 1,121,712